python之多線程(一)

多線程 VS 多進程

  • 程序: 一堆代碼以文本形式存入一個文檔
  • 進程: 程序運行的一個狀態 
    • 包含地址空間,內存,數據債等
    • 每一進程由自己完全獨立的運行環境,多進程共享數據是一個問題
  • 線程 
    • 一個進程的獨立運行片段,一個進程可以由多個線程
    • 輕量化的進程
    • 一個進程的多個線程間共享數據和上下文運行環境
    • 共享互斥問題
  • 全局解釋器鎖(GIL) 
    • Python代碼的執行是由python虛擬機進行控制
    • 在主循環中有切只有一個控制線程在執行
  • Python包 
    • thread : 有問題,不好用,python3改成了_thread
    • threading: 通行的包
  • 案例01

 

'''
利用time函數,生產兩個函數
順序調用
計算總的運行時間
'''
import time


def loopl():
    # ctime 得到當前時間
    print('Statr loop l at : ', time.ctime())
    # 睡眠多長時間,單位是秒
    time.sleep(4)
    print('End loop l at : ', time.ctime())


def loop2():
    # ctime 得到當前時間
    print('Start loop 2 at : ', time.ctime())
    # 睡眠多長時間,單位是秒
    time.sleep(2)
    print('End loop 2 at : ', time.ctime())


def main():
    print('Starting at : ', time.ctime())
    loopl()
    loop2()
    print('All done at : ', time.ctime())


if __name__ == '__main__':
    main()
Starting at :  Sat Jun 30 14:35:17 2018
Statr loop l at :  Sat Jun 30 14:35:17 2018
End loop l at :  Sat Jun 30 14:35:21 2018
Start loop 2 at :  Sat Jun 30 14:35:21 2018
End loop 2 at :  Sat Jun 30 14:35:23 2018
All done at :  Sat Jun 30 14:35:23 2018

啓用多線程

 

# -*- coding:utf-8 -*-
'''
利用time函數,生產兩個函數
順序調用
計算總的運行時間
'''

import time
import _thread as thread


def loopl():
    # ctime 得到當前時間
    print('Statr loop l at : ', time.ctime())
    # 睡眠多長時間,單位是秒
    time.sleep(4)
    print('End loop l at : ', time.ctime())


def loop2():
    # ctime 得到當前時間
    print('Start loop 2 at : ', time.ctime())
    # 睡眠多長時間,單位是秒
    time.sleep(2)
    print('End loop 2 at : ', time.ctime())


def main():
    print('Starting at : ', time.ctime())
    # 啓動多線程的意思是用多線程去執行某個函數
    # 啓動多線程函數爲start_new_thread
    # 參數兩個,一個是需要運行的函數名,第二個是函數的參數作爲元祖使用,爲空則使用空元祖
    # 注意⚠️:如果函數只有一個參數,需要參數後有一個逗號
    thread.start_new_thread(loopl, ())
    thread.start_new_thread(loop2, ())

    print('All done at : ', time.ctime())


if __name__ == '__main__':
    main()
    time.sleep(5)
Starting at :  Sat Jun 30 14:55:11 2018
All done at :  Sat Jun 30 14:55:11 2018
Start loop 2 at :  Sat Jun 30 14:55:11 2018
Statr loop l at :  Sat Jun 30 14:55:11 2018
End loop 2 at :  Sat Jun 30 14:55:13 2018
End loop l at :  Sat Jun 30 14:55:15 2018

帶參數的函數,多線程執行例子

# -*- coding:utf-8 -*-
'''
利用time函數,生產兩個函數
順序調用
計算總的運行時間
'''

import time
import _thread as thread


def loopl(param):
    # ctime 得到當前時間
    print('Statr loop l at : ', time.ctime())
    # 打印傳入參數
    print("參數 param is :" + param)
    # 睡眠多長時間,單位是秒
    time.sleep(4)
    print('End loop l at : ', time.ctime())


def loop2(name, name2):
    # ctime 得到當前時間
    print('Start loop 2 at : ', time.ctime())
    # 打印參數
    print("姓名1:" + name, "姓名2 :", name2)
    # 睡眠多長時間,單位是秒
    time.sleep(2)
    print('End loop 2 at : ', time.ctime())


def main():
    print('Starting at : ', time.ctime())
    # 啓動多線程的意思是用多線程去執行某個函數
    # 啓動多線程函數爲start_new_thread
    # 參數兩個,一個是需要運行的函數名,第二個是函數的參數作爲元祖使用,爲空則使用空元祖
    # 注意⚠️:如果函數只有一個參數,需要參數後有一個逗號
    thread.start_new_thread(loopl, ("今天天氣不錯",))
    thread.start_new_thread(loop2, ("王大拿","王呵呵"))
    print('All done at : ', time.ctime())


if __name__ == '__main__':
    main()
    # 一定要有while語句,不然主線程結束,子線程也結束
    #while True:
    time.sleep(5)

threading的使用 

 - 直接利用threading.Thread生成Thread實例

            - t = threading.Thread(target=xxx,args=(xxx,))

            - t.statr(): 啓動多線程

            - t.join(): 等待多線程執行完成 

# -*- coding:utf-8 -*-
'''
利用time函數,生產兩個函數
順序調用
計算總的運行時間
'''

import time
import threading


def loopl(param):
    # ctime 得到當前時間
    print('Statr loop l at : ', time.ctime())
    # 打印傳入參數
    print("參數 param is :" + param)
    # 睡眠多長時間,單位是秒
    time.sleep(4)
    print('End loop l at : ', time.ctime())


def loop2(name, name2):
    # ctime 得到當前時間
    print('Start loop 2 at : ', time.ctime())
    # 打印參數
    print("姓名1:" + name, "姓名2 :", name2)
    # 睡眠多長時間,單位是秒
    time.sleep(2)
    print('End loop 2 at : ', time.ctime())


def main():
    print('Starting at : ', time.ctime())
    # 啓動多線程的意思是用多線程去執行某個函數
    # 參數兩個,一個是需要運行的函數名,第二個是函數的參數作爲元祖使用,爲空則使用空元祖
    # 注意⚠️:如果函數只有一個參數,需要參數後有一個逗號
    t1 = threading.Thread(target=loopl, args=("老王頭",))
    t1.start()

    t2 = threading.Thread(target=loop2, args=("張芃芃", "李冬面",))
    t2.start()

    print('All done at : ', time.ctime())


if __name__ == '__main__':
    main()
Starting at :  Sat Jun 30 15:11:00 2018
Statr loop l at :  Sat Jun 30 15:11:00 2018
參數 param is :老王頭
Start loop 2 at : All done at :  Sat Jun 30 15:11:00 2018
 Sat Jun 30 15:11:00 2018
姓名1:張芃芃 姓名2 : 李冬面
End loop 2 at :  Sat Jun 30 15:11:02 2018
End loop l at :  Sat Jun 30 15:11:04 2018

 

JOIN()用法

  • join等線程執行完成後繼續往下執行
# -*- coding:utf-8 -*-
'''
利用time函數,生產兩個函數
順序調用
計算總的運行時間
'''

import time
import threading


def loopl(param):
    # ctime 得到當前時間
    print('Statr loop l at : ', time.ctime())
    # 打印傳入參數
    print("參數 param is :" + param)
    # 睡眠多長時間,單位是秒
    time.sleep(4)
    print('End loop l at : ', time.ctime())


def loop2(name, name2):
    # ctime 得到當前時間
    print('Start loop 2 at : ', time.ctime())
    # 打印參數
    print("姓名1:" + name, "姓名2 :", name2)
    # 睡眠多長時間,單位是秒
    time.sleep(2)
    print('End loop 2 at : ', time.ctime())


def main():
    print('Starting at : ', time.ctime())
    # 啓動多線程的意思是用多線程去執行某個函數
    # 參數兩個,一個是需要運行的函數名,第二個是函數的參數作爲元祖使用,爲空則使用空元祖
    # 注意⚠️:如果函數只有一個參數,需要參數後有一個逗號
    t1 = threading.Thread(target=loopl, args=("老王頭",))
    t1.start()

    t2 = threading.Thread(target=loop2, args=("張芃芃", "李冬面",))
    t2.start()
    # 等待兩個線程都執行完畢,才繼續往下執行
    t1.join()
    t2.join()

    print('All done at : ', time.ctime())


if __name__ == '__main__':
    main()

 守護線程

- 如果在程序中將子線程設置成守護線程,則子線程會在主線程結束的時候自動退出

- 一般認爲,守護線程不重要或者不運行離開主線程獨立運行

- 守護線程案例能否有效果跟環境相關 

# 非守護線程例子
# -*- coding:utf-8 -*-

import time
import threading


def fun():
    print("Strat fun")
    time.sleep(2)
    print("End fun")


print("Main thread")

t1 = threading.Thread(target=fun, args=())
t1.start()

time.sleep(1)

print("Main thread end")
Main thread
Strat fun
Main thread end
End fun

 

# 守護線程例子
# -*- coding:utf-8 -*-

import time
import threading


def fun():
    print("Strat fun")
    time.sleep(2)
    print("End fun")


print("Main thread")

t1 = threading.Thread(target=fun, args=())
# 使用守護線程的方法,必須在start之前設置,否則無效
t1.setDaemon(True)
t1.start()

time.sleep(1)

print("Main thread end")
Main thread
Strat fun
Main thread end
End fun

線程常用屬性

- threading.currentThread: 返回當前線程變量

- threading.enumerate: 返回一個包含正在運行的線程list,正在運行的線程指的是線程啓動後,結束前的線程

- threading.activeCount: 返回正在運行的線程數量

- thr.setName: 設置線程名稱

- thr.getName: 獲取線程名稱 

# -*- coding:utf-8 -*-
'''
利用time函數,生產兩個函數
順序調用
計算總的運行時間
'''

import time
import threading


def loopl(param):
    # ctime 得到當前時間
    print('Statr loop l at : ', time.ctime())
    # 打印傳入參數
    print("參數 param is :" + param)
    # 睡眠多長時間,單位是秒
    time.sleep(4)
    print('End loop l at : ', time.ctime())


def loop2(name, name2):
    # ctime 得到當前時間
    print('Start loop 2 at : ', time.ctime())
    # 打印參數
    print("姓名1:" + name, "姓名2 :", name2)
    # 睡眠多長時間,單位是秒
    time.sleep(2)
    print('End loop 2 at : ', time.ctime())


def main():
    print('Starting at : ', time.ctime())
    t1 = threading.Thread(target=loopl, args=("老王頭",))
    t1.setName("THR_1_loop1")
    t1.start()

    t2 = threading.Thread(target=loop2, args=("張芃芃", "李冬面",))
    t2.setName("THR_2_loop2")
    t2.start()

    # 3秒後,線程2結束運行
    time.sleep(3)

    # enumerate 得到正在運行子線程,及子線程1

    for thr in threading.enumerate():
        print("正在運行的線程名字是: {0}".format(thr.getName()))

    print("正在運行的子線程數量爲:{0}".format(threading.activeCount()))

    print('All done at : ', time.ctime())


if __name__ == '__main__':
    main()
Starting at :  Sat Jun 30 15:39:41 2018
Statr loop l at :  Sat Jun 30 15:39:41 2018
參數 param is :老王頭
Start loop 2 at :  Sat Jun 30 15:39:41 2018
姓名1:張芃芃 姓名2 : 李冬面
End loop 2 at :  Sat Jun 30 15:39:43 2018
正在運行的線程名字是: MainThread
正在運行的線程名字是: Thread-2
正在運行的線程名字是: Thread-3
正在運行的線程名字是: IPythonHistorySavingThread
正在運行的線程名字是: Thread-1
正在運行的線程名字是: THR_1_loop1
正在運行的子線程數量爲:6
All done at :  Sat Jun 30 15:39:44 2018
End loop l at :  Sat Jun 30 15:39:45 2018

 直接繼承自threading.Thread

- 直接繼承Thread

- 重寫run()

- 類實例可以直接運行 

普通寫法 

# 直接繼承threading.Thread 重寫run方法
import threading
import time


class ThreadFunc(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global n, lock
        time.sleep(1)
        if lock.acquire():
            print(n,self.name)
            n, self.name
            n += 1
            lock.release()


if "__main__" == __name__:
    n = 1
    ThreadList = []
    lock = threading.Lock()
    for i in range(1, 200):
        t = ThreadFunc()
        ThreadList.append(t)
    for t in ThreadList:
        t.start()
    for t in ThreadList:
        t.join()

 企業寫法

import threading
from time import sleep, ctime

loop = [4, 2]


class ThreadFunc:
    def __init__(self, name):
        self.name = name

    def loop(self, nloop, nsec):
        '''
        :param nloop: loop函數的名稱
        :param nsec: 系統休眠時間
        :return:
        '''
        print("Start loop ", nloop, 'at ', ctime())
        sleep(nsec)
        print("Done loop ", nloop, 'at ', ctime())


def main():
    print("Starting at ", ctime())
    # ThreadFunc("loop").loop 跟以下兩個式子相當:
    # t = ThreadFunc("loop")
    # t.loop

    # 以下t1 和 t2 的定義方式相等
    t = ThreadFunc("loop")

    t1 = threading.Thread(target=t.loop, args=('LOOP1', 4))
    # 以下寫法更西方化,工業化
    t2 = threading.Thread(target=ThreadFunc('loop').loop, args=('LOOP2', 2))

    # 常見錯誤寫法
    # t1 = threading.Thread(target=ThreadFunc('loop').loop(100,4))
    # t2 = threading.Thread(target=ThreadFunc('loop').loop(100,2))

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print("ALL done at ", ctime())


if __name__ == '__main__':
    main()
Starting at  Sat Jun 30 16:00:49 2018
Start loop  LOOP1 at  Sat Jun 30 16:00:49 2018
Start loop  LOOP2 at  Sat Jun 30 16:00:49 2018
Done loop  LOOP2 at  Sat Jun 30 16:00:51 2018
Done loop  LOOP1 at  Sat Jun 30 16:00:53 2018
ALL done at  Sat Jun 30 16:00:53 2018

 

 

 

 

發佈了36 篇原創文章 · 獲贊 24 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章