Pyhton多線程

在了解多線程前先給大家介紹下並發和並行:

   並發:多個任務一起執行 在多任務之間快速切換處理 任務數量大於cpu核數

   並行:一個cpu核處理一個任務,多個cpu核同時處理多個任務 任務數量等於或者小於cpu核數 

再介紹下同步和異步 :

  同步:指線程在訪問某一資源時,獲得了資源的返回結果之後才會執行其他操作(先做某件事,再做某件事) 

  異步: 與同步相對,是指線程在訪問某一資源時,無論是否取得返回結果,都進行下一步操作;當有了資源返回結果時 系統自會通知線程

在Python中,使用threading庫來創建多線程

import threading      def func1():      for i in range(6):          time.sleep(1)      def func2():      for i in range(5):          time.sleep(1)      # 創建線程對象  t2 = threading.Thread(target=func2)  # target = 方法名  t1 = threading.Thread(target=func1, name='線程1')  # 可以設置線程名字  # start 啟動線程活動  # join([time]) 設置主線程會等待time秒後再往下執行,time默認為子線程結束,多個子線程之間設置的值會增加  # isAlive 返回線程是否活動的  # getName() 返回線程名  # setName() 設置線程名    a = time.time()  t2.start()  # 開始執行線程2  t1.start()  # 開始執行線程1  # 讓主線程等待子線程執行完後再繼續往下執行 同步的概念  t2.join()  t1.join()  b = time.time()  c = b - a  print(c)    threading.currentThread()  # 返回當前執行的線程  threading.enumerate()  # 返回正在運行的所有線程(list) 正在運行指:啟動後、結束前,不包括了啟動前和終止後的線程  threading.activeCount()  # 返回正在運行的線程數量

在threading庫中調用start方法後,start方法調用了他內部的run()方法,我們可以通過繼承threading重寫run()方法來批量創建線程,代碼如下

import threading  import requests  import time      # 通過繼承 threading 類來創建線程 重寫run方法  因為start方法調用的就是run 重寫run  class MyClass(threading.Thread):      def __init__(self, url):          self.url = url          super().__init__()  # 如果要傳入參數重寫init方法時,一定要調用父類的init方法        # 發送requests請求        def run(self):          res = requests.get(self.url)          print('線程{},返回{}'.format(threading.current_thread(), res.status_code))      t1 = time.time()  for i in range(5):      t = MyClass('https://www.baidu.com')      t.start()  t.join()  t2 = time.time()  print(t2 - t1)

可以通過直接實例化類來創建線程對象,如果要傳入參數,在重寫init方法時要注意在最後調用父類的init方法,具體原因可以去查看thrreading庫是如何實現的,在init方法中有很多其他的代碼需要執行。

多線程共享全局變量:

在python中是使用單核來處理線程的,也就是並發並非並行,代碼示例如下:

import threading    a = 100      def func1():      for i in range(100000):          global a          a += 1      print(a)      def func2():      for i in range(100000):          global a          a += 1      print(a)      t1 = threading.Thread(func1())  t2 = threading.Thread(func2())  t1.start()  t2.start()

當執行func1()方法時,獲取全局變量為100,此時暫停切換到func2()方法,獲取全局變量a為100,並進入for循環,當a循環到20000時(舉例),又切換到func1()方法中開始執行for循環,此時在func1()中a的值為100,循環1次後把a的值又更新為101,造成數據不準確。

解決這個問題會用到互斥鎖、同步、隊列,在下一篇會給大家講到