首頁  >  文章  >  後端開發  >  Python多執行緒中阻塞(join)與鎖(Lock)使用誤區解析

Python多執行緒中阻塞(join)與鎖(Lock)使用誤區解析

不言
不言原創
2018-04-27 10:53:312924瀏覽

這篇文章主要為大家詳細 介紹了Python多執行緒中阻塞join與鎖Lock的使用誤區,具有一定的參考價值,有興趣的小夥伴們可以參考一下

關於阻塞主執行緒

##join的錯誤用法

Thread.join() 作用為阻塞主執行緒,即在子執行緒未返回的時候,主執行緒等待其返回然後再繼續執行.

join不能與start在循環裡連用

以下為錯誤代碼,代碼創建了5個線程,然後用一個循環激活線程,激活之後令其阻塞主線程.

threads = [Thread() for i in range(5)]
for thread in threads:
  thread.start()
  thread.join()

執行過程:


1. 第一次迴圈中,主執行緒透過start函數啟動執行緒1,執行緒1進行計算.

2.由於start函數不會阻塞主執行緒,在執行緒1進行運算的同時,主執行緒向下執行join函數.
3. 執行join之後,主執行緒被執行緒1阻塞,在執行緒1回傳結果之前,主執行緒無法執行下一輪循環.
4. 線程1計算完成之後,解除對主線程的阻塞.
5. 主線程進入下一輪循環,激活線程2並被其阻塞…

#如此往復,可以看出,本來應該並發的五個線程,在這裡變成了順序隊列,效率和單線程無異.

join的正確用法

使用兩個循環分別處理

startjoin函數.即可實現並發.

##
threads = [Thread() for i in range(5)]
for thread in threads:
  thread.start()
for thread in threads:
  thread.join()

time.sleep代替join進行調試

之前在一些項目裡看到過這樣的代碼,使用time.sleep代替join手動阻塞主線程.

在所有子線程返回之前,主線程陷入無線循環而不能退出.


for thread in threads:
  thread.start()
while 1:
  if thread_num == 0:
    break
  time.sleep(0.01)

關於線程鎖定(threading.Lock)

單核心CPU PIL是否還需要鎖定?

非原子操作

count = count 1

理論上是線程不安全的. 使用3個線程同時執行上述操作改變全域變數count的值,並查看程式執行結果. 如果結果正確,則表示未出現執行緒衝突.

使用下列程式碼測試

# -*- coding: utf-8 -*-
import threading
import time
count = 0
class Counter(threading.Thread):
  def __init__(self, name):
    self.thread_name = name
    super(Counter, self).__init__(name=name)
  def run(self):
    global count
    for i in xrange(100000):
      count = count + 1
counters = [Counter('thread:%s' % i) for i in range(5)]
for counter in counters:
  counter.start()
time.sleep(5)
print 'count=%s' % count

執行結果:

count=275552

事實上每次運行結果都不相同且不正確,這證明單核心CPU PIL仍無法保證執行緒安全,需要加鎖.

加上鎖定後的正確程式碼:

# -*- coding: utf-8 -*-
import threading
import time
count = 0
lock = threading.Lock()
class Counter(threading.Thread):
  def __init__(self, name):
    self.thread_name = name
    self.lock = threading.Lock()
    super(Counter, self).__init__(name=name)
  def run(self):
    global count
    global lock
    for i in xrange(100000):
      lock.acquire()
      count = count + 1
      lock.release()


counters = [Counter('thread:%s' % i) for i in range(5)]

for counter in counters:
  counter.start()

time.sleep(5)
print 'count=%s' % count

#結果:

count=500000


##注意鎖的全局性

這是一個簡單的Python語法問題,但在邏輯複雜時有可能被忽略.

要保證鎖對於多個子線程來說是共用的,即不要在Thread的子類內部創建鎖定.

以下為

#錯誤代碼

# -*- coding: utf-8 -*-

import threading
import time
count = 0
# lock = threading.Lock() # 正确的声明位置
class Counter(threading.Thread):
  def __init__(self, name):
    self.thread_name = name
    self.lock = threading.Lock() # 错误的声明位置
    super(Counter, self).__init__(name=name)
  def run(self):
    global count
    for i in xrange(100000):
      self.lock.acquire()
      count = count + 1
      self.lock.release()
counters = [Counter('thread:%s' % i) for i in range(5)]

for counter in counters:
  print counter.thread_name
  counter.start()

time.sleep(5)
print 'count=%s' % count

相關推薦:

python執行緒中同步鎖定詳解

python多執行緒之事件Event的使用詳解############python執行緒池threadpool的實作########################

以上是Python多執行緒中阻塞(join)與鎖(Lock)使用誤區解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn