1. 程式人生 > >Python多執行緒中阻塞(join)與鎖(Lock)的使用誤區

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執行阻塞(join)(Lock)的使用誤區

關於阻塞主執行緒 join的錯誤用法 Thread.join() 作用為阻塞主執行緒,即在子執行緒未返回的時候,主執行緒等待其返回然後再繼續執行. join不能與start在迴圈裡連用 以下為錯誤程式碼,程式碼建立了5個執行緒,然後用一個迴圈啟用執行緒,

Python執行join函式的使用含義

wechat:812716131 ------------------------------------------------------ 技術交流群請聯絡上面wechat ----------------------------------------------

徹底理解Python執行的setDaemonjoin【配有GIF示意】

在進行Python多執行緒程式設計時, join() 和 setDaemon() 是最常用的方法,下面說說兩者的用法和區別。 1、join () 例子:主執行緒A中,建立了子執行緒B,並且在主執行緒A中呼叫了B.join(), 那麼,主執行緒A會在呼叫的地方阻塞,

python執行join()

    先看一個例子,該例子沒用到join。    新增一個執行緒,輸出“start”和“finish”標記執行緒的開始和結束。執行緒added_thread和執行緒main同時執行,其中added_thread消耗較長的時間(通過執行緒sleep模擬)。mian執行結束後

Python執行join函式setDaemon函式使用說明

      在Python多執行緒程式設計的時候,經常需要用到join函式和setDaemon函式。之前對這兩個函式一直理解不是很到位。今天查閱了很多資料,對兩個函式的認識更加的深入一些了。       join([timeout])可以參考Python文件說明。大概意思就

執行join(),yield()優先順序Priority

1、join():join()方法使呼叫該方法的執行緒在此之前執行完畢,也就是等待該方法的執行緒執行完畢後再往下繼續執行。注意該方法也需要捕捉異常。 ublic class Test { public static void main(String[] args) {

python執行daemon的屬性方法

我們看官方介紹是這樣的: 意思就是說:這個屬性為一個布林值,表示是否為一個守護程序,且這個屬性設定必須線上程的start方法開始之前呼叫。它的值繼承自主執行緒,主執行緒的daemon為False且所有從主執行緒建立的執行緒都是daemon = False 。 下面一句

執行的waitsleep到底誰釋放了

首先,多執行緒中會使用到兩個延遲的函式,wait和sleep。 wait是Object類中的方法,而sleep是Thread類中的方法。 sleep是Thread類中的靜態方法。無論是在a執行緒中呼

java執行關於join方法的使用

Thread的非靜態方法join()讓一個執行緒B“加入”到另外一個執行緒A的尾部。在A執行完畢之前,B不能工作。例如:         Thread t = new MyThread();         t.start();         t.join(); 另外,j

java執行對於join方法的理解

對於多執行緒的join方法一直理解得很模糊,大致看了一些資料,JDK是這樣說的:join public final void join (long millis )throws InterruptedException Waits at most millis

Java執行Join和Interrupt()方法的使用

更多詳細的解答請轉至:http://my.oschina.net/summerpxy/blog/198457;http://uule.iteye.com/blog/1101994;(比如有一個執行緒t.當在Main執行緒中呼叫t.join()的時候,那麼Main執行緒必須拿

java執行join方法詳解

 方法Join是幹啥用的? 簡單回答,同步,如何同步? 怎麼實現的? 下面將逐個回答。     自從接觸Java多執行緒,一直對Join理解不了。JDK是這樣說的:join public final void join(long millis)throws InterruptedException Wait

執行join方法——原始碼分析

join方法的作用是等待執行緒銷燬,當主執行緒中呼叫了其他執行緒的join方法時,主執行緒需要等到該執行緒執行完畢才可以繼續執行,示例如下: public class MyThread extends Thread { public void ru

執行的wait() 的關係

我們先看一段程式碼: /** * 計算輸出其他執行緒鎖計算的資料 * */ public class ThreadA { public static void main(String[] args) throws InterruptedException{ Thre

python執行和GIL全域性直譯器

1、執行緒     執行緒被稱為輕量級程序,是最小執行單元,系統排程的單位。執行緒切換需要的資源一般,效率一般。  2、多執行緒         在單個程式中同時執行多個執行緒完成不同的工作,稱為多執行緒 3、

Python執行讀寫檔案加

Python的多執行緒在io方面比單執行緒還是有優勢,但是在多執行緒開發時,少不了對檔案的讀寫操作。在管理多個執行緒對同一檔案的讀寫操作時,就少不了檔案鎖了。 使用fcntl 在linux下,python的標準庫有現成的檔案鎖,來自於fcntl模組。這個模組提供了unix

Java執行的物件互斥

1、為什麼會有鎖? 在看執行緒同步的問題之前,我們先看一個生活中的小例子: 我拿著銀行卡去ATM取錢,假如我的卡里有3000塊,我要取走2000,這個時候,ATM會去銀行的資料庫裡查詢我的賬戶是否有2000以上的餘額,如果有,就會讓我取走,不幸的是,這個時候

python執行程式設計(3): 使用互斥同步執行

問題的提出 上一節的例子中,每個執行緒互相獨立,相互之間沒有任何關係。現在假設這樣一個例子:有一個全域性的計數num,每個執行緒獲取這個全域性的計數,根據num進行一些處理,然後將num加1。很容易寫出這樣的程式碼: # encoding: UTF-8import

python執行event的使用-----------------即一個靈活的方法標誌位,類似於java的等待喚醒機制(pythonjava不同的地方)

event是python中一個特有的標誌位方法,他一共有三種方法 1.event.wait():如果標誌位設定了,它不做任何事,如果沒有設定,則將會鎖住,等待標誌位的設定 2.event.set():設定標誌位 3.event.clear():清除標誌位 這一種機制很

執行sleep() wait() yield() join(), interrupt(),stop(),suspend()用法區別

網上卻是有很多的關於這個的答案,但是都長得一樣,為了寫這篇部落格,自己找了幾個例子。 JoinThread: package com.com.aaa.threadJoinDemo; public c