Python-線程、線程池

1. Python多線程

python3中常用的線程模塊為:_thread(Python2中的thread)、threading(推薦)
線程池:ThreadPoolExecutor

2. 使用線程

第一種方式:

_thread.start_new_thread(function,args[,kwargs])
function:線程函數(shù)
args:傳遞給線程函數(shù)的參數(shù),必須是tuple(元組)類型
kwargs:可選參數(shù)

第二種方式

import threading
import time
import traceback

class MyThread(threading.Thread):
    def __init__(self, thread_id, thread_name, counter):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.thread_name = thread_name
        self.counter = counter

    def run(self):
        print_time(self.thread_name, 1, self.counter)

def print_time(thread_name, delay, counter):
    while counter:
        time.sleep(delay)
        print('%s : %s ' % (thread_name, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())))
        counter -= 1

thread1 = MyThread(1, 'time_thread_1', 5)
thread1.start()

3. thread內(nèi)部方法

1.threading.currentThread():返回當(dāng)前的線程變量;
2.threading.enumerate():返回當(dāng)前正在運行的線程list,正在運行是指線程啟動后、結(jié)束前;
3.threading.activeCount():返回當(dāng)前正在運行的線程數(shù),與len(threading.enumerate())相同
4.run():用以表示線程互動的方法
5.start():啟動線程
6.join([time]):等待線程終止,阻塞線程,直至join被調(diào)用或者線程中止、正常退出或者異常,或者超時[time]
7.isAlive():返回線程是否存活
8.getName():線程名
9.setName():設(shè)置線程名

4. 線程同步

如果多個線程同時修改某個數(shù)據(jù)可能會導(dǎo)致數(shù)據(jù)的正確性,所以需要對線程進行同步處理,使用 Thread 對象的 Lock 和 Rlock 可以實現(xiàn)簡單的線程同步,這兩個對象都有 acquire 方法和 release 方法,對于那些需要每次只允許一個線程操作的數(shù)據(jù),可以將其操作放到 acquire 和 release 方法之間。

如下實例,多個線程同時進行對某個數(shù)據(jù)進行自增,未加鎖時結(jié)果會怎么樣?

import threading

class MyThread(threading.Thread):
    def __init__(self, thread_id, thread_name):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.thread_name = thread_name

    def run(self):
        #獲取鎖
        # threadLock.acquire()
        global number
        for i in range(1, 1000000):
            number += 1
        #釋放鎖
        # threadLock.release()

threadLock = threading.Lock()

number = 1

thread = MyThread(1, 'thread')
thread.start()

thread2 = MyThread(2, 'thread2')
thread2.start()
計算結(jié)果=1999999 ? 1313434

Process finished with exit code 0

如果把加鎖的注釋去掉會怎么樣呢?

    def run(self):
        #獲取鎖
        threadLock.acquire()
        global number
        for i in range(1, 1000000):
            number += 1
        #釋放鎖
        threadLock.release()
計算結(jié)果=1999999 ? 1999999

Process finished with exit code 0

5. 線程池

1. 線程池介紹

線程池在系統(tǒng)啟動時即創(chuàng)建大量空閑的線程,程序只要將一個函數(shù)提交給線程池,線程池就會啟動一個空閑的線程來執(zhí)行它。當(dāng)該函數(shù)執(zhí)行結(jié)束后,該線程并不會死亡,而是再次返回到線程池中變成空閑狀態(tài),等待執(zhí)行下一個函數(shù)。
使用線程池可以有效地控制系統(tǒng)中并發(fā)線程的數(shù)量。當(dāng)系統(tǒng)中包含有大量的并發(fā)線程時,會導(dǎo)致系統(tǒng)性能急劇下降,甚至導(dǎo)致 Python 解釋器崩潰,而線程池的最大線程數(shù)參數(shù)可以控制系統(tǒng)中并發(fā)線程的數(shù)量不超過此數(shù)。

2.線程池的使用

線程池的基類是 concurrent.futures 模塊中的 Executor,Executor 提供了兩個子類,即 ThreadPoolExecutor 和 ProcessPoolExecutor,其中 ThreadPoolExecutor 用于創(chuàng)建線程池,而 ProcessPoolExecutor 用于創(chuàng)建進程池。

Exectuor 提供了如下常用方法:
submit(fn, *args, **kwargs):將 fn 函數(shù)提交給線程池。*args 代表傳給 fn 函數(shù)的參數(shù),*kwargs 代表以關(guān)鍵字參數(shù)的形式為 fn 函數(shù)傳入?yún)?shù)。
map(func, *iterables, timeout=None, chunksize=1):該函數(shù)類似于全局函數(shù) map(func, *iterables),只是該函數(shù)將會啟動多個線程,以異步方式立即對 iterables 執(zhí)行 map 處理。
shutdown(wait=True):關(guān)閉線程池。

submit 方法會返回一個 Future 對象
Future 提供了如下方法:

cancel():取消該 Future 代表的線程任務(wù)。如果該任務(wù)正在執(zhí)行,不可取消,則該方法返回 False;否則,程序會取消該任務(wù),并返回 True。
cancelled():返回 Future 代表的線程任務(wù)是否被成功取消。
running():如果該 Future 代表的線程任務(wù)正在執(zhí)行、不可被取消,該方法返回 True。
done():如果該 Funture 代表的線程任務(wù)被成功取消或執(zhí)行完成,則該方法返回 True。
result(timeout=None):獲取該 Future 代表的線程任務(wù)最后返回的結(jié)果。如果 Future 代表的線程任務(wù)還未完成,該方法將會阻塞當(dāng)前線程,其中 timeout 參數(shù)指定最多阻塞多少秒。
exception(timeout=None):獲取該 Future 代表的線程任務(wù)所引發(fā)的異常。如果該任務(wù)成功完成,沒有異常,則該方法返回 None。
add_done_callback(fn):為該 Future 代表的線程任務(wù)注冊一個“回調(diào)函數(shù)”,當(dāng)該任務(wù)成功完成時,程序會自動觸發(fā)該 fn 函數(shù)。

在用完一個線程池后,應(yīng)該調(diào)用該線程池的 shutdown() 方法,該方法將啟動線程池的關(guān)閉序列。調(diào)用 shutdown() 方法后的線程池不再接收新任務(wù),但會將以前所有的已提交任務(wù)執(zhí)行完成。當(dāng)線程池中的所有任務(wù)都執(zhí)行完成后,該線程池中的所有線程都會死亡。

from concurrent.futures import ThreadPoolExecutor
import threading, time


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

    def run(self) -> None:
        print('start run task')
        time.sleep(2)
        print('task finish\n')
        return '線程類執(zhí)行完成'

def test(thread_name):
    print(thread_name, threading.current_thread().name)
    time.sleep(5)
    print('任務(wù)完成\n')
    return '線程方法執(zhí)行完成'

f __name__ == '__main__':
    thread_pool = ThreadPoolExecutor(5)
    futures = []
    for i in range(7):
        thraed = WorkThread()
        # sumit(方法名,參數(shù))
        future1 = thread_pool.submit(thraed.run)
        future2 = thread_pool.submit(test, i)
        futures.append(future1)
        futures.append(future2)

    def get_call_back(future):
        # 監(jiān)聽任務(wù)執(zhí)行結(jié)果,當(dāng)前線程一直阻塞知道有結(jié)果,但是不阻塞主線程
        print(future.result())

    for future in futures:
        #添加監(jiān)聽
        future.add_done_callback(get_call_back)

     print('main thread')

map執(zhí)行線程
啟動三個線程

thread_pool.map(test, (2,3,4))
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【JAVA 線程】 線程 進程:是一個正在執(zhí)行中的程序。每一個進程執(zhí)行都有一個執(zhí)行順序。該順序是一個執(zhí)行路徑,或者...
    Rtia閱讀 2,893評論 2 20
  • 前段時間遇到這樣一個問題,有人問微信朋友圈的上傳圖片的功能怎么做才能讓用戶的等待時間較短,比如說一下上傳9張圖片,...
    加油碼農(nóng)閱讀 1,285評論 0 2
  • 轉(zhuǎn)自http://www.cnblogs.com/dolphin0520/p/3932921.html Java并...
    Allen_cyn閱讀 2,007評論 0 4
  • 從HR的崗位轉(zhuǎn)到PM的崗位上有大半年了。雖然人力工作不是日常工作的重點,但是始終沒有離開這個圈子。我覺得人...
    XuYing_6e2e閱讀 105評論 0 0
  • 燈籠靜靜睡在桌上 鞭炮聲成了催眠曲 煙花便是床頭的燈 燈下的燈籠熄滅了光 彩中映著紅 紅里泛著彩 幾絲纓絡(luò)垂下 隨...
    岑遙閱讀 255評論 0 0

友情鏈接更多精彩內(nèi)容