1. 程式人生 > >python裡的多執行緒

python裡的多執行緒

面向過程建立執行緒

import threading
import time


def sing(a):
    # threading.current_thread().name:建立執行緒時name的值
    print('執行緒為:{},接收過來的引數為:{}'.format(threading.current_thread().name,a))
    for x in range(1, 3):
        print('我在唱歌')
        time.sleep(1)


def dance(a):
    # threading.current_thread().name:建立執行緒時name的值
    print('執行緒為:{},接收過來的引數為:{}'.format(threading.current_thread().name,a))
    for x in range(1, 3):
        print('我在跳舞')
        time.sleep(1)


def main():
    a = '我是執行緒引數'
    # 建立第1個唱歌執行緒,
    # target:該執行緒執行起來時執行的函式,
    # name:給該執行緒起個名字,
    # args:一個元組,用於給執行緒執行的函式內傳遞引數
    tsing = threading.Thread(target=sing, name='唱歌', args=(a,))

    # 建立第2個跳舞執行緒
    tdance = threading.Thread(target=dance, name='跳舞', args=(a,))

    # 啟動第1個執行緒
    tsing.start()
    # 啟動第2個執行緒
    tdance.start()

    # 讓主執行緒等待指定的子執行緒結束之後再結束
    tsing.join()
    tdance.join()

    # 主執行緒在執行
    print('我是主執行緒')


if __name__ == '__main__':
    main()

執行結果為:
執行緒為唱歌,接收過來的引數為我是執行緒引數
我在唱歌
執行緒為跳舞,接收過來的引數為我是執行緒引數
我在跳舞
我在唱歌
我在跳舞
我是主執行緒

面向物件建立執行緒

import threading
import time


# 寫一個類,繼承自threading.Thread
# main
class OneThread(threading.Thread):
    # 如果需要接收執行緒的名字和給執行緒傳遞的引數可以寫到__init__裡
    def __init__(self, name, a):
        # 因為這裡繼承自threading.Thread類,需要呼叫一下父類的__init__方法,
        # 否則會出錯
        super().__init__()
        self.name = name
        self.a = a

    # run方法名字必須為run,下面啟動執行緒時會自動執行run方法
    def run(self):
        print('執行緒名字是:{},接收的引數是:{}'.format(self.name, self.a))
        for x in range(1, 6):
            print('我是執行緒1')
            time.sleep(1)


class TowThread(threading.Thread):
    def __init__(self, name, a):
        super().__init__()
        self.name = name
        self.a = a

    def run(self):
        print('執行緒名字是:{},接收的引數是:{}'.format(self.name, self.a))
        for x in range(1, 6):
            print('我是執行緒2')
            time.sleep(1)


def main():
    # 啟動兩個執行緒
    one = OneThread('one', '我是執行緒1傳遞的引數')
    tow = TowThread('tow', '我是執行緒2傳遞的引數')

    # 啟動兩個執行緒
    one.start()
    tow.start()

    # 讓主執行緒等待子執行緒結束
    one.join()
    tow.join()

    print('主執行緒和子執行緒全部結束')


if __name__ == '__main__':
    main()

執行結果為:

執行緒名字是:one,接收的引數是:我是執行緒1傳遞的引數
我是執行緒1
執行緒名字是:tow,接收的引數是:我是執行緒2傳遞的引數
我是執行緒2
我是執行緒1
我是執行緒2
我是執行緒2
我是執行緒1
我是執行緒2
我是執行緒1
我是執行緒1
我是執行緒2
主執行緒和子執行緒全部結束

執行緒同步

        執行緒之間共享全域性變數,但當其中一個執行緒正在修改一個全域性變數時,另一個執行緒也訪問了這個全域性變數,那麼訪問的是第一個執行緒修改之前的全域性變數還是修改之後的全域性變數呢?這個時候需要用到執行緒鎖,但還有一個問題,比如現在有3個執行緒要用到一個全域性變數,第一個執行緒先搶到了這個全域性變數,並加了執行緒鎖,那麼剩下的兩個執行緒只能等,等第一個執行緒執行完畢,釋放執行緒鎖時再去搶,以此類推,所以執行緒執行沒有順序.

import threading
# 建立鎖
suo = threading.Lock()

# 上鎖
suo.acquire()

# 釋放鎖
suo.release()

佇列(生產者消費者)

      

from queue import Queue

# 建立佇列,括號內的數字指定了這個佇列內最多放多少個元素,
# 不寫的話代表任意個數
q = Queue(5)
# 向佇列中新增資料(生產者)
q.put('老王')
q.put('老李')
q.put('老宋')
q.put('老張')
q.put('老楊')

# 當佇列中元素已經滿了後,再往裡面新增資料,程式會阻塞到這裡不執行,
# 直到佇列中的元素被拿出去後再執行
# q.put('第6個數據')
# 也可以在後面寫上一個False,代表隊列滿了之後再往裡新增直接丟擲異常
# q.put('第6個數據', False)
# 如果佇列滿了,程式等待3秒後,佇列還是滿的才會拋異常
# q.put('第6個數據', True, 3)

# 從佇列中取資料(消費者)
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())

# 當佇列中沒資料後再取,程式會阻塞在這裡,等待隊裡中出現新資料後再執行
# print(q.get())
# 也可以新增False,當隊裡中沒資料時再取的話拋異常
# print(q.get(False))
# 當隊裡內沒資料時等待3秒,3秒過後還是沒有資料拋異常
# print(q.get(True,3))

# 判斷佇列是否為空
q.empty()
# 判斷佇列是否已滿
q.full()
# 獲取佇列長度
q.qsize()

# print(q)