Python 多執行緒學習02

2021-07-08 12:32:03 字數 3936 閱讀 4205

這一次的目的是, 兩個執行緒以方式合作,列印0-9的十個數字。不要漏,也不要重複。

於是在上乙個程式的基礎上,修改一下, 因為數字都存在content這個列表中,每次乙個執行緒先pop()出乙個數字,再列印,這樣,每個數字就只能被列印一次了。 效果怎樣呢? 試試吧。

修改後的程式為:

#coding:utf8

import threading,random

import time

class

cut(threading.thread):

def__init__

(self,content):

threading.thread.__init__(self)

self.content = content

defrun(self):

while(len(content) > 0):

time.sleep(random.randrange(0,2))

tmp = content.pop()

print self.getname(), tmp

if'__main__' == __name__:

filename = "easy.txt"

f = open(filename)

content = f.read().split("\n")

content = content[:-1]

print content

workman = cut(content)

workman2 = cut(content)

workman.start()

workman2.start()

f.close()

我反覆執行了幾次,幾乎都是這樣的結果。

[[email protected]

.4.100 thread]# python work.py

['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

thread-1

9thread-1

8thread-2

7thread-2

6thread-2

5thread-1

4thread-2

3thread-2

2thread-2

1thread-2

0exception in thread thread-1:

traceback (most recent call last):

file

"/usr/local/python2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner

self.run()

file

"work.py", line 16, in run

tmp = content.pop()

indexerror: pop from empty list

[[email protected]

.4.100 thread]#

從這個結果來看 ,一開始 程式執行的還不錯。 從9,8,7… 兩個執行緒爭著從content的列表中pop()到數字,然後列印出來 ,但程式最後還是丟擲了異常, 說執行緒1 在空的list上 pop()資料。 從程式上來看 ,我們是 先 驗證 len(content) >0 ,才會進去迴圈中去 pop()資料的, 那為什麼還會異常呢?

原因就是 執行緒1 在進入while 後,先sleep 了乙個短暫的時間 , 在這時候, 執行緒2,搶險把 最後乙個數字0 給pop()出來了, 從列印結果也能夠看出 ,執行緒2 最後列印出了0 , 然後 執行緒1 ,還繼續去pop()乙個已經空了的list, 就導致了異常。

就好像,你檢視火車票還有1張, 可是當要付款的時候,告訴你已經賣光了是一樣的。

又好像,你約會了乙個女生,但吃飯的時候,卻發現她在和別人一起吃飯。

導致這個問題的原因有兩個:

1, 執行緒1和執行緒2 都有許可權訪問這個 list ,都可以去pop()資料。

2, 檢視list是否為空,和從list中pop資料 是兩個動作,不是乙個整體。 誠然,這兩個動作卻是不是乙個整體 。但是對於這個列表來說, 應該是乙個整體 ,你才不會出錯。

換句話說, 在乙個執行緒去檢視list的時候,就要把這個list 霸佔住。 因為後面還有乙個pop()的動作 ,等你pop()完畢之後,再釋放開它。

就像你約了人吃飯, 你就把她佔住,等吃了這頓飯, 她愛跟吃飯 那是以後的事了, 起碼這頓不行。

這就是為什麼 最好乙個女生只交乙個男朋友的原因, 否則,吃飯時候,老是競爭,你多難受。

解決這個問題,程式語言提供有好幾個方法, 但有多少種方法並不重要, 只要能解決問題就行。

與占有相關的 是乙個叫做 鎖的東西。 把乙個東西鎖住,就是希望這個東西不被除了你意外的人使用。

關於鎖的文件,這兒有乙份,16.2.2 和 16.2.3

lock objects

a primitive lock is in one of two states, 「locked」 or 「unlocked」. it is created in the unlocked state. it has two basic methods, acquire() and release(). when the state is unlocked, acquire() changes the state to locked and returns immediately. when the state is locked, acquire() blocks until a call to release() in another thread changes it to unlocked, then the acquire() call resets it to locked and returns. the release() method should only be called in the locked state; it changes the state to unlocked and returns immediately. if an attempt is made to release an unlocked lock, a threaderror will be raised.

when more than one thread is blocked in acquire() waiting for the state to turn to unlocked, only one thread proceeds when a release() call resets the state to unlocked; which one of the waiting threads proceeds is not defined, and may vary across implementations.

我用我蹩腳的中文和蹩腳的英文來翻譯一下這小段。

有兩種鎖,這種是 lock, 這是一種原裝鎖,類似原裝進口的意思。只有 鎖住 和 沒鎖住 兩個狀態。 這個鎖剛建立出來是沒鎖住的。 它有兩個方法 acquire() 和 release() 鎖住和 釋放。

當鎖沒鎖住時候,acquire() 會使得這個鎖鎖住, 相當於占有了。

當鎖已經是鎖住狀態了, 還有人想繼續acquire()怎麼辦, 他就等待了, 等待 直到你前面那個人釋放了, 你再鎖。

release() 這個方法的意思是開鎖,或者釋放 。 但只有當鎖是鎖住的時候, 你才可以呼叫這個方法去解鎖 。 如果乙個鎖,本來就是開著的, 你依然要呼叫這個release()方法去解鎖 試試, 那麼 threaderror 這個異常就丟擲了。

假設乙個女生有三個男朋友, 現在這個女生和乙個男生去吃飯了 , 其他兩個男的也餓了 ,都在這兒排隊等著, 只有 等 第乙個男的吃完了, 後面這兩個人,才會有乙個 會去跟 那女孩子吃飯。 但是 至於 到底是 後面哪個男生能夠得到 機會 去和女生吃飯呢? 這個問題沒有定義 ,沒有答案, 不是說誰先來的,誰後來的,完全看命。

利用lock的實現的版本,留到下文吧。

Python 多執行緒 (02)

當多個執行緒同時訪問乙個變數的時候,會產生共享變數的問題。問題解決 鎖 是乙個標誌,表示乙個執行緒正在占用一些資源 訊號燈 鎖的使用方法 上鎖,使用共享資源,放心的用,取消鎖,釋放鎖。案例1import threading sum 0 loopsum 1000000 lock threading.l...

多執行緒02

什麼是使用者態和核心態 在作業系統裡面,作業系統的核心佔一部分記憶體,使用者應用程式佔一部分記憶體,核心即可以訪問自身的記憶體,也可以訪問使用者應用程式的記憶體,但是使用者應用程式只能訪問自身的記憶體,不能訪問核心的記憶體 執行緒的啟動 關閉 切換都要依賴於核心態 voliate 保證執行緒可見性 ...

多執行緒02 執行緒建立

1 方式一 繼承 thread 類,重寫run 方法,呼叫start 開啟執行緒 public class thread01 extends thread main 是主線程 public static void main string args throws interruptedexceptio...