亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

python線程中的同步問題及解決方法

系統 1772 0

多線程開發可能遇到的問題

假設兩個線程t1和t2都要對num=0進行增1運算,t1和t2都各對num修改1000000次,num的最終的結果應該為2000000。但是由于是多線程訪問,有可能出現下面情況:

            
from threading import Thread
import time
num = 0
def test1():
  global num
  for i in range(1000000):
    num += 1
  print("--test1--num=%d" % num)
def test2():
  global num
  for i in range(1000000):
    num += 1
  print("--test2--num=%d" % num)
if __name__ == '__main__':
  Thread(target=test1).start()
  Thread(target=test2).start()
  print("num = %d" % num)
"""
num = 134116
--test1--num=1032814
--test2--num=1166243
"""
          

運行結果可能不一樣,但是結果往往不是2000000。問題產生的原因就是沒有控制多個線程對同一資源的訪問,對數據造成破壞,使得線程運行的結果不可預期。這種現象稱為“線程不安全”。

線程同步――使用互斥鎖

如果多個線程共同對某個數據修改,則可能出現不可預料的結果,為了保證數據的正確性,需要對多個線程進行同步。
使用 Thread 對象的 Lock 和 Rlock 可以實現簡單的線程同步,這兩個對象都有 acquire 方法和 release 方法,對于那些需要每次只允許一個線程操作的數據,可以將其操作放到 acquire 和 release 方法之間。

使用互斥鎖實現上面的例子:

            
from threading import Thread, Lock
import time
num = 0
def test1():
  global num
  # 上鎖
  mutex.acquire()
  for i in range(1000000):
    num += 1
  # 解鎖
  mutex.release()
  print("--test1--num=%d" % num)
def test2():
  global num
  mutex.acquire()
  for i in range(1000000):
    num += 1
  mutex.release()
  print("--test2--num=%d" % num)
start_time = time.time() # 開始時間
# 創建一把互斥鎖,默認沒有上鎖
mutex = Lock()
p1 = Thread(target=test1)
p1.start()
# time.sleep(3)  # 取消屏蔽之后 再次運行程序,結果會不一樣,,,為啥呢?
p2 = Thread(target=test2)
p2.start()
p1.join()
p2.join()
end_time = time.time() # 結束時間
print("num = %d" % num)
print("運行時間:%fs" % (end_time - start_time)) # 結束時間-開始時間
"""
輸出結果:
--test1--num=1000000
--test2--num=2000000
num = 2000000
運行時間:0.287206s
"""
          

同步的應用――多個線程有序執行

            
from threading import Lock, Thread
from time import sleep
class Task1(Thread):
  def run(self):
    while True:
      # 判斷是否上鎖成功,返回值為bool類型
      if lock1.acquire():
        print("--task1--")
        sleep(0.5)
        lock2.release()
class Task2(Thread):
  def run(self):
    while True:
      if lock2.acquire():
        print("--task2--")
        sleep(0.5)
        lock3.release()
class Task3(Thread):
  def run(self):
    while True:
      if lock3.acquire():
        print("--task3--")
        sleep(0.5)
        lock1.release()

if __name__ == '__main__':  
  # 創建一把鎖
  lock1 = Lock()  
  # 創建一把鎖,并且鎖上
  lock2 = Lock()
  lock2.acquire()  
  # 創建一把鎖,并且鎖上
  lock3 = Lock()
  lock3.acquire()  
  t1 = Task1()
  t2 = Task2()
  t3 = Task3()  
  t1.start()
  t2.start()
  t3.start()
"""
--task1--
--task2--
--task3--
--task1--
--task2--
--task3--
--task1--
--task2--
...
"""
          

生產者與消費者模式

為什么要使用生產者和消費者模式

在線程世界里,生產者就是生產數據的線程,消費者就是消費數據的線程。在多線程開發當中,如果生產者處理速度很快,而消費者處理速度很慢,那么生產者就必須等待消費者處理完,才能繼續生產數據。同樣的道理,如果消費者的處理能力大于生產者,那么消費者就必須等待生產者。為了解決這個問題于是引入了生產者和消費者模式。

什么是生產者消費者模式

生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞隊列來進行通訊,所以生產者生產完數據之后不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列里取,阻塞隊列就相當于一個緩沖區,平衡了生產者和消費者的處理能力。

Python的Queue模塊中提供了同步的、線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(后入先出)隊列LifoQueue,和優先級隊列PriorityQueue。這些隊列都實現了鎖原語(可以理解為原子操作,即要么不做,要么就做完),能夠在多線程中直接使用。可以使用隊列來實現線程間的同步。

用FIFO隊列實現上述生產者與消費者問題的代碼如下:

            
import threading
import time
from queue import Queue
class Producer(threading.Thread):
  def run(self):
    global queue
    count = 0
    while True:
      if queue.qsize() < 1000:
        for i in range(100):
          count += 1
          msg = "生成產品" + str(count)
          queue.put(msg)
          print(msg)
      time.sleep(0.5)
class Consumer(threading.Thread):
  def run(self):
    global queue
    while True:
      if queue.qsize() > 100:
        for i in range(3):
          msg = self.name + "消費了" + queue.get()
          print(msg)
      time.sleep(0.5)
          

ThreadLocal

在多線程環境下,每個線程都有自己的數據。一個線程使用自己的局部變量比使用全局變量好,因為局部變量只有線程自己能看見,不會影響其他線程,而全局變量的修改必須加鎖。
ThreadLocal解決了參數在一個線程中各個函數之間互相傳遞的問題

            
import threading
"""
?個ThreadLocal變量雖然是全局變量,但每個線程都只能讀寫??線程的獨
?副本,互不?擾。
"""
# 創建全局ThreadLocal對象:
local_school = threading.local()
def process_student():
  # 獲取當前線程關聯的student:
  std = local_school.student
  print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
  # 綁定ThreadLocal的student:
  local_school.student = name
  process_student()
t1 = threading.Thread(target=process_thread, args=('dongGe',), name="Thread-A")
t2 = threading.Thread(target=process_thread, args=('?王',), name="Thread-B")
t1.start()
t2.start()
          

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产精品夜色一区二区三区 | 一级毛片免费的 | 国产精品亚洲综合第一区 | 久久麻豆视频 | 综合久久综合 | 久久综合九色综合97婷婷女人 | 狠狠狠狼鲁欧美综合网免费 | 天天拍夜夜拍 | jizz中国女人 | 日本高清中文字幕在线观穿线视频 | 色婷亚洲 | 深夜网站在线 | 一本大道久久a久久综合 | 日韩欧美国产中文 | 黑人和黑人激情一级毛片 | 亚洲国产成人资源在线桃色 | 国产亚洲欧美日韩在线看片 | 日韩一区国产二区欧美三 | 国产 高清 在线 | a级日本理论片在线播放 | 欧洲a视频 | 免费亚洲视频 | 波多野结衣免费播放 | 久久天天躁狠狠躁夜夜爽蜜月 | 国产福利在线免费观看 | 色久激情 | 免费一级毛片 | 欧美交换乱理伦片120秒 | 99久久久国产精品免费播放器 | 亚洲综合狠狠99婷婷 | 99精品国产高清一区二区 | 欧美高清在线视频在线99精品 | 欧美特黄a级高清免费大片 欧美特黄a级猛片a级 | 男人在线资源 | 一级有奶水毛片免费看 | 亚洲精品国产啊女成拍色拍 | 日韩国产午夜一区二区三区 | 国产精品免费视频一区一 | 久久精品影院一区二区三区 | 夜夜草天天干 | 九九热伊人|