Python多線程使用技巧(同步 + 異步 + 強制結束多線程)


使用方法都寫在程序裏面的註釋中,請盡情享用,如果您覺得不錯可以點個贊哦🙂

多線程同步(函數化)

代碼如下:

"""
多線程同步(函數化)
"""
# -*- coding:utf-8 -*-
import threading
import datetime
import time

__author__ = 'Evan'
locks = None
thread_pool = None


def unit_test(sleep_time):
    """
    多線程單元測試
    :param sleep_time: 睡眠時間
    :return:
    """
    # locks.acquire()   獲取鎖 -- 獲取鎖之後,其他的線程在此等待

    with thread_pool:  # 使用線程池控制多線程進入的數量,超過限定數量在此阻塞
        print('current thread name {}'.format(threading.current_thread().name))  # 當前線程名
        print('{} --> start sleep_time ({})'.format(datetime.datetime.now(), sleep_time))
        time.sleep(sleep_time)
        print('{} --> sleep_time ({}) finish'.format(datetime.datetime.now(), sleep_time))

    # locks.release()   釋放鎖 -- 如果不釋放鎖,後續的線程會一直被阻塞不能進入


def thread_run(sleep_list):
    """
    執行多線程
    :param sleep_list: 睡眠時間列表
    :return:
    """
    global locks, thread_pool

    locks = threading.Lock()  # 線程鎖
    max_value = 3  # 設置可同時執行的最大線程數爲3
    thread_pool = threading.Semaphore(value=max_value)  # 初始化線程池
    print('線程池最大數量:{}'.format(max_value))

    threads = []
    for i in sleep_list:  # 配置所有線程
        t = threading.Thread(target=unit_test, args=(i,))
        threads.append(t)

    for thread in threads:  # 開啓所有線程
        thread.start()
        while True:
            # 判斷正在運行的線程數量, 控制執行的線程數量永遠爲4-1=3個
            if len(threading.enumerate()) <= 4:
                # threading.enumerate()包括主線程和所有的活動子線程,長度最少爲1
                print('剩餘活動線程數量: {}'.format(len(threading.enumerate())))
                break

    # TODO thread.join()和下面的while循環都可阻塞所有線程,依據情況進行選擇
    # for thread in threads:  # 主線程在此阻塞,等待所有線程結束
    #     thread.join()

    while True:
        # 當線程數量等於1時,並且只剩下一個主線程,退出循環
        if len(threading.enumerate()) == 1 and 'MainThread(MainThread' in str(threading.enumerate()[0]):
            break

    print('所有線程執行結束')


def main():
    thread_run(sleep_list=[3, 2, 6, 1, 7, 5, 8])


if __name__ == '__main__':
    main()

執行結果:

線程池最大數量:3
current thread name Thread-1剩餘活動線程數量: 2

2020-04-16 17:37:40.504859 --> start sleep_time (3)
current thread name Thread-2剩餘活動線程數量: 3

2020-04-16 17:37:40.504859 --> start sleep_time (2)
current thread name Thread-3剩餘活動線程數量: 4

2020-04-16 17:37:40.511841 --> start sleep_time (6)
2020-04-16 17:37:42.512497 --> sleep_time (2) finish
剩餘活動線程數量: 4
current thread name Thread-4
2020-04-16 17:37:42.512497 --> start sleep_time (1)
2020-04-16 17:37:43.510862 --> sleep_time (3) finish2020-04-16 17:37:43.516815 --> sleep_time (1) finish
剩餘活動線程數量: 4

current thread name Thread-5
2020-04-16 17:37:43.516815 --> start sleep_time (7)
current thread name Thread-6
剩餘活動線程數量: 4
2020-04-16 17:37:43.516815 --> start sleep_time (5)
2020-04-16 17:37:46.529807 --> sleep_time (6) finish
current thread name Thread-7
2020-04-16 17:37:46.535790 --> start sleep_time (8)
剩餘活動線程數量: 4
2020-04-16 17:37:48.523479 --> sleep_time (5) finish
2020-04-16 17:37:50.523099 --> sleep_time (7) finish
2020-04-16 17:37:54.542362 --> sleep_time (8) finish
所有線程執行結束

多線程同步(使用父類繼承方法)

代碼如下:

"""
多線程同步(使用父類繼承方法)
"""
# -*- coding:utf-8 -*-
import threading
import time
import datetime

__author__ = 'Evan'


class Test(threading.Thread):  # 繼承threading.Thread類

    def __init__(self, sleep_time, thread_pool):
        super().__init__()  # 執行父類的構造方法
        self.sleep_time = sleep_time
        self.thread_pool = thread_pool  # 線程池句柄

    def run(self):
        """
        改寫父類run方法,需要執行的多線程函數寫在這裏
        :return:
        """
        print('current thread name {}'.format(threading.current_thread().name))  # 當前線程名
        print('{} --> start sleep_time ({})'.format(datetime.datetime.now(), self.sleep_time))
        time.sleep(self.sleep_time)
        print('{} --> sleep_time ({}) finish'.format(datetime.datetime.now(), self.sleep_time))
        self.thread_pool.release()  # 釋放線程鎖,可用線程數加1


if __name__ == '__main__':
    max_value = 4
    pool = threading.Semaphore(value=max_value)  # 線程池(設置可同時執行的最大線程數爲4)
    print('線程池最大數量:{}'.format(max_value))

    for i in [3, 2, 6, 1, 7]:
        pool.acquire()  # 獲得線程鎖,可用線程數減1
        t = Test(sleep_time=i, thread_pool=pool)  # 實例化線程類
        t.start()  # 開啓線程(線程會自動執行run方法)

執行結果:

線程池最大數量:4
current thread name Thread-1
2020-02-24 12:57:52.198842 --> start sleep_time (3)
current thread name Thread-2
2020-02-24 12:57:52.199840 --> start sleep_time (2)
current thread name Thread-3
2020-02-24 12:57:52.199840 --> start sleep_time (6)
current thread name Thread-4
2020-02-24 12:57:52.199840 --> start sleep_time (1)
2020-02-24 12:57:53.200647 --> sleep_time (1) finish
current thread name Thread-5
2020-02-24 12:57:53.202368 --> start sleep_time (7)
2020-02-24 12:57:54.200846 --> sleep_time (2) finish
2020-02-24 12:57:55.199718 --> sleep_time (3) finish
2020-02-24 12:57:58.200735 --> sleep_time (6) finish
2020-02-24 12:58:00.202727 --> sleep_time (7) finish

多線程異步

代碼如下:

"""
多線程異步
"""
# -*- coding:utf-8 -*-
import time
import datetime
from concurrent.futures import ThreadPoolExecutor

__author__ = 'Evan'


def unit_test(sleep_time):
    """
    多線程單元測試
    :param sleep_time: 睡眠時間
    :return:
    """
    print('{} --> start sleep_time ({})'.format(datetime.datetime.now(), sleep_time))
    time.sleep(sleep_time)
    print('{} --> sleep_time ({}) finish'.format(datetime.datetime.now(), sleep_time))


def main():
    max_value = 4  # 線程池最大數量
    thread_pool = ThreadPoolExecutor(max_workers=max_value)  # 初始化線程池
    print('線程池最大數量:{}'.format(max_value))

    # 異步多線程運行不會阻塞主線程,異步線程隊列滿了後會繼續往下運行主線程,等隊列釋放後又回到異步線程繼續執行
    for i in [3, 2, 6, 1, 7]:
        thread_pool.submit(unit_test, i)
    print('{} --> 我是主線程'.format(time.ctime()))


if __name__ == '__main__':
    main()

執行結果:

線程池最大數量:4
2020-02-24 13:00:35.349155 --> start sleep_time (3)
2020-02-24 13:00:35.349155 --> start sleep_time (2)
2020-02-24 13:00:35.350151 --> start sleep_time (6)
2020-02-24 13:00:35.350151 --> start sleep_time (1)
Mon Feb 24 13:00:35 2020 --> 我是主線程
2020-02-24 13:00:36.351237 --> sleep_time (1) finish
2020-02-24 13:00:36.351237 --> start sleep_time (7)
2020-02-24 13:00:37.350428 --> sleep_time (2) finish
2020-02-24 13:00:38.350457 --> sleep_time (3) finish
2020-02-24 13:00:41.351857 --> sleep_time (6) finish
2020-02-24 13:00:43.352244 --> sleep_time (7) finish

強制結束多線程

代碼如下:

"""
強制結束線程方法:
1> 使用stop_thread函數關閉指定的單個線程
2> 設置當前函數爲守護進程,函數結束後會關閉所有的子線程 --> Set daemon=True
"""
# -*- coding:utf-8 -*-
import threading
import time
import inspect
import ctypes


def stop_thread(tid, exctype=SystemExit):
    tid = ctypes.c_long(tid.ident)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("Invalid thread id")
    elif res != 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


def use_stop_thread_function():
    def test_1():
        while True:
            print('-------')
            time.sleep(1)

    print('Use stop thread function')
    t = threading.Thread(target=test_1)
    t.start()
    time.sleep(5)
    stop_thread(tid=t)
    print('Threads have been stopped')


class UseDaemonFunction(object):

    def test_2(self, times):
        time.sleep(times)
        print('times: {}'.format(times))

    def main(self):
        # 設置主線程
        self.threads = threading.Thread(target=self._main, args=())
        self.threads.start()

    def _main(self):
        print('Use daemon function')
        threads = []
        for i in range(20):
            # 開啓20個子線程
            t = threading.Thread(target=self.test_2, args=(i, ))
            t.daemon = True  # 設置當前函數爲守護進程
            threads.append(t)

        for i in threads:
            i.start()

        for i in threads:
            i.join()
        print('Threads have been stopped')


if __name__ == "__main__":
    # use_stop_thread_function()
    # ————分割線————
    use_daemon_funcion = UseDaemonFunction()
    use_daemon_funcion.main()  # 執行20個子線程

    time.sleep(5)
    # 殺死主線程,所有的子線程都會被關閉
    stop_thread(tid=use_daemon_funcion.threads)
    print('All done')

執行結果:

Use daemon function
times: 0
times: 1
times: 2
times: 3
times: 4
All done
times: 5
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章