2018-09-13-day19-多執行緒

weixin_33809981發表於2018-09-13
  • 多執行緒基礎

  1. 主執行緒
    每個程式預設都會有一個執行緒,這個執行緒我們一般叫他主執行緒。
    預設情況下,所有的程式碼都是在主執行緒中執行的

  2. 子執行緒
    一個程式中可以有多個執行緒,除了主執行緒以外,其他執行緒需要手動的新增

  3. threading是python中的一個內建模組,用來支援多執行緒
    a. Thread類的物件就是執行緒物件,需要執行緒的時候,就建立這個類或者這個類的子類物件
    b. threading.currentThread()---->用來獲取當前執行緒物件

import threading
import datetime
import time

# 下載兩個電影
def download(file):
    print(threading.currentThread())
    print('開始下載:{:<6}\t'.format(file),datetime.datetime.now())
    # 讓執行緒阻塞5秒
    time.sleep(5)
    print('{:<6}\t下載結束\t'.format(file), datetime.datetime.now())


if __name__ == '__main__':
    print('主執行緒中的程式碼')
    #print(threading.currentThread())
    # 在子執行緒中取下載兩個電影
    """
    threading.Thread(target=)
    target:需要在子執行緒中呼叫的函式的函式名
    args:在被呼叫函式的實參
    返回值:建立好的執行緒物件
    """
    thread1 = threading.Thread(target=download, args=('終結者',))
    thread1.setDaemon(True)
    # 開始執行t1對應執行緒中的任務
    thread1.start()
    thread2 = threading.Thread(target=download, args=('五行天',))
    thread2.setDaemon(True)
    # 想要在子執行緒中執行任務,必須通過執行緒物件呼叫start方法
    thread2.start()

    print('============================================')
  • 重寫執行緒Thread的run方法

物件導向實現多執行緒技術
1. 宣告一個類繼承自Thread類
2. 重寫run方法,將需要在子執行緒中執行的任務放在run方法中
3. 在需要子執行緒的位置去建立這個類的物件,然後用物件去呼叫start方法去執行run中的任務

"""
class Download(Thread):
    def __init__(self, file):
        super().__init__()
        self.file = file
    def run(self):
        print('開始下載:{:<6}\t'.format(self.file,), datetime.datetime.now())
        time.sleep(randint(5,10))
        print('下載結束:{:<6}\t'.format(self.file), datetime.datetime.now())

if __name__ == '__main__':
    print('===================================')
    t1 = Download('沉默的羔羊')
    t1.start()
    t2 = Download('恐怖遊輪')
    t2.start()

    print('+++++++++++++++++++++++++++++++++++')

  • 執行緒的join方法

在兩個子執行緒中下載兩個電影,在主執行緒中取統計兩個電影的下載
的總時間
如果希望某個執行緒結束後才執行某個操作,就用那個執行緒呼叫join方法
"""
class DownloadThread(Thread):
    def __init__(self, file):
        super().__init__()
        self.file = file

    def run(self):
        print('開始下載:{:<6}\t'.format(self.file, ), datetime.datetime.now())
        time.sleep(randint(5, 15))
        print('下載結束:{:<6}\t'.format(self.file), datetime.datetime.now())

if __name__ == '__main__':
    t1 = DownloadThread('沉默的羔羊')
    t2 = DownloadThread('美麗人生')
    start = time.time()
    t1.start()
    t2.start()
    # 系統t1和t2的程式碼都結束後才執行下面的程式碼
    t1.join()   # 這句程式碼後面的程式碼在t1對應的執行緒結束就才執行
    t2.join()
    end = time.time()
    print(end-start)
  • 多執行緒資料的共享問題

多個執行緒修改同一個變數時,有可能會導致資料混亂,所以儘量不要多執行緒改變同一個變數,如果要,需要加鎖lock

from threading import Thread, Lock
import datetime
import time
from random import randint


"""
模擬多個人操作同一個賬戶

同步鎖和互斥鎖:
"""

class Account:
    """賬號類"""
    def __init__(self, balance):
        # 餘額
        self.balance = balance
        self.lock = Lock()


    # 讀出原來的餘額,確定錢的一系列操作,將原來的餘額加上存的數額再存到賬戶
    def save_money(self, amount):
        # 獲取原來的餘額
        print('開始存錢')
        self.lock.acquire()
        old_amount = self.balance
        # 模擬時間消耗
        time.sleep(5)
        # 修改餘額
        self.balance  = old_amount + amount
        print('存取成功,餘額:{}'.format(self.balance))
        self.lock.release()

    def get_money(self, amount):
        print('開始取錢')
        old_amount = self.balance
        if old_amount < amount:
            print('餘額不足!')
            return
        time.sleep(5)
        self.balance = old_amount - amount
        print('取錢成功,餘額{}'.format(self.balance))

    def show_balance(self):
        print('餘額為:{}'.format(self.balance))

if __name__ == '__main__':
    """
    當多個執行緒對一個資料操作的時候可能會出現資料混亂
    """
    account = Account(1000)
    t1 = Thread(target=account.save_money, args=(200,))
    t2 = Thread(target=account.save_money, args=(1300,))
    #t3 = Thread(target=account.get_money, args=(800,))
    t1.start()
    t2.start()
    #t3.start()
    t1.join()
    t2.join()
    #t3.join()
    account.show_balance()

相關文章