python線程同步
A. python多線程
那是當然。你這樣寫就可以了
self.p[:]=array
這樣寫法的含義就是指針不變。只換內容。這樣就可以同步了。
你的寫法是,新建一個數組,再把指針緞帶self.p,如果其它的線程就會出問題。
另外你的p應該放在__init__之前。引用時使用T.p來引用,這樣更合理一些。
B. Python中進程與線程的區別是什麼
Num01–>線程
線程是操作系統中能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。
一個線程指的是進程中一個單一順序的控制流。
一個進程中可以並發多條線程,每條線程並行執行不同的任務。
Num02–>進程
進程就是一個程序在一個數據集上的一次動態執行過程。
進程有以下三部分組成:
1,程序:我們編寫的程序用來描述進程要完成哪些功能以及如何完成。
2,數據集:數據集則是程序在執行過程中需要的資源,比如圖片、音視頻、文件等。
3,進程式控制制塊:進程式控制制塊是用來記錄進程的外部特徵,描述進程的執行變化過程,系統可以用它來控制和管理進程,它是系統感知進程存在的唯一標記。
Num03–>進程和線程的區別:
1、運行方式不同:
進程不能單獨執行,它只是資源的集合。
進程要操作CPU,必須要先創建一個線程。
所有在同一個進程里的線程,是同享同一塊進程所佔的內存空間。
2,關系
進程中第一個線程是主線程,主線程可以創建其他線程;其他線程也可以創建線程;線程之間是平等的。
進程有父進程和子進程,獨立的內存空間,唯一的標識符:pid。
3,速度
啟動線程比啟動進程快。
運行線程和運行進程速度上是一樣的,沒有可比性。
線程共享內存空間,進程的內存是獨立的。
4,創建
父進程生成子進程,相當於復制一份內存空間,進程之間不能直接訪問
創建新線程很簡單,創建新進程需要對父進程進行一次復制。
一個線程可以控制和操作同級線程里的其他線程,但是進程只能操作子進程。
5,交互
同一個進程里的線程之間可以直接訪問。
兩個進程想通信必須通過一個中間代理來實現。
相關推薦:《Python視頻教程》
Num04–>幾個常見的概念
1,什麼的並發和並行?
並發:微觀上CPU輪流執行,宏觀上用戶看到同時執行。因為cpu切換任務非常快。
並行:是指系統真正具有同時處理多個任務(動作)的能力。
2,同步、非同步和輪詢的區別?
同步任務:B一直等著A,等A完成之後,B再執行任務。(打電話案例)
輪詢任務:B沒有一直等待A,B過一會來問一下A,過一會問下A
非同步任務:B不需要一直等著A, B先做其他事情,等A完成後A通知B。(發簡訊案例)
Num05–>進程和線程的優缺點比較
首先,要實現多任務,通常我們會設計Master-Worker模式,Master負責分配任務,Worker負責執行任務,因此,多任務環境下,通常是一個Master,多個Worker。
如果用多進程實現Master-Worker,主進程就是Master,其他進程就是Worker。
如果用多線程實現Master-Worker,主線程就是Master,其他線程就是Worker。
多進程模式最大的優點就是穩定性高,因為一個子進程崩潰了,不會影響主進程和其他子進程。(當然主進程掛了所有進程就全掛了,但是Master進程只負責分配任務,掛掉的概率低)著名的Apache最早就是採用多進程模式。
多進程模式的缺點是創建進程的代價大,在Unix/Linux系統下,用fork調用還行,在Windows下創建進程開銷巨大。另外,操作系統能同時運行的進程數也是有限的,在內存和CPU的限制下,如果有幾千個進程同時運行,操作系統連調度都會成問題。
多線程模式通常比多進程快一點,但是也快不到哪去,而且,多線程模式致命的缺點就是任何一個線程掛掉都可能直接造成整個進程崩潰,因為所有線程共享進程的內存。在Windows上,如果一個線程執行的代碼出了問題,你經常可以看到這樣的提示:「該程序執行了非法操作,即將關閉」,其實往往是某個線程出了問題,但是操作系統會強制結束整個進程。
在Windows下,多線程的效率比多進程要高,所以微軟的IIS伺服器默認採用多線程模式。由於多線程存在穩定性的問題,IIS的穩定性就不如Apache。為了緩解這個問題,IIS和Apache現在又有多進程+多線程的混合模式,真是把問題越搞越復雜。
Num06–>計算密集型任務和IO密集型任務
是否採用多任務的第二個考慮是任務的類型。我們可以把任務分為計算密集型和IO密集型。
第一種:計算密集型任務的特點是要進行大量的計算,消耗CPU資源,比如計算圓周率、對視頻進行高清解碼等等,全靠CPU的運算能力。這種計算密集型任務雖然也可以用多任務完成,但是任務越多,花在任務切換的時間就越多,CPU執行任務的效率就越低,所以,要最高效地利用CPU,計算密集型任務同時進行的數量應當等於CPU的核心數。
計算密集型任務由於主要消耗CPU資源,因此,代碼運行效率至關重要。Python這樣的腳本語言運行效率很低,完全不適合計算密集型任務。對於計算密集型任務,最好用C語言編寫。
第二種:任務的類型是IO密集型,涉及到網路、磁碟IO的任務都是IO密集型任務,這類任務的特點是CPU消耗很少,任務的大部分時間都在等待IO操作完成(因為IO的速度遠遠低於CPU和內存的速度)。對於IO密集型任務,任務越多,CPU效率越高,但也有一個限度。常見的大部分任務都是IO密集型任務,比如Web應用。
IO密集型任務執行期間,99%的時間都花在IO上,花在CPU上的時間很少,因此,用運行速度極快的C語言替換用Python這樣運行速度極低的腳本語言,完全無法提升運行效率。對於IO密集型任務,最合適的語言就是開發效率最高(代碼量最少)的語言,腳本語言是首選,C語言最差。
相關推薦:
Python中的進程是什麼
C. 簡述python進程,線程和協程的區別及應用場景
協程多與線程進行比較
1) 一個線程可以多個協程,一個進程也可以單獨擁有多個協程,這樣python中則能使用多核CPU。
2) 線程進程都是同步機制,而協程則是非同步
3) 協程能保留上一次調用時的狀態,每次過程重入時,就相當於進入上一次調用的狀態
D. python多線程怎樣同步
鎖機制
�6�9�6�9threading的Lock類,用該類的acquire函數進行加鎖,用realease函數進行解鎖
import threading
import time
class Num:
def __init__(self):
self.num = 0
self.lock = threading.Lock()
def add(self):
self.lock.acquire()#加鎖,鎖住相應的資源
self.num += 1
num = self.num
self.lock.release()#解鎖,離開該資源
return num
n = Num()
class jdThread(threading.Thread):
def __init__(self,item):
threading.Thread.__init__(self)
self.item = item
def run(self):
time.sleep(2)
value = n.add()#將num加1,並輸出原來的數據和+1之後的數據
print(self.item,value)
for item in range(5):
t = jdThread(item)
t.start()
t.join()#使線程一個一個執行
�6�9�6�9當一個線程調用鎖的acquire()方法獲得鎖時,鎖就進入「locked」狀態。每次只有一個線程可以獲得鎖。如果此時另一個線程試圖獲得這個鎖,該線程就會變為「blocked」狀態,稱為「同步阻塞」(參見多線程的基本概念)。
�6�9�6�9直到擁有鎖的線程調用鎖的release()方法釋放鎖之後,鎖進入「unlocked」狀態。線程調度程序從處於同步阻塞狀態的線程中選擇一個來獲得鎖,並使得該線程進入運行(running)狀態。
信號量
�6�9�6�9信號量也提供acquire方法和release方法,每當調用acquire方法的時候,如果內部計數器大於0,則將其減1,如果內部計數器等於0,則會阻塞該線程,知道有線程調用了release方法將內部計數器更新到大於1位置。
import threading
import time
class Num:
def __init__(self):
self.num = 0
self.sem = threading.Semaphore(value = 3)
#允許最多三個線程同時訪問資源
def add(self):
self.sem.acquire()#內部計數器減1
self.num += 1
num = self.num
self.sem.release()#內部計數器加1
return num
n = Num()
class jdThread(threading.Thread):
def __init__(self,item):
threading.Thread.__init__(self)
self.item = item
def run(self):
time.sleep(2)
value = n.add()
print(self.item,value)
for item in range(100):
t = jdThread(item)
t.start()
t.join()
條件判斷
�6�9�6�9所謂條件變數,即這種機制是在滿足了特定的條件後,線程才可以訪問相關的數據。
�6�9�6�9它使用Condition類來完成,由於它也可以像鎖機制那樣用,所以它也有acquire方法和release方法,而且它還有wait,notify,notifyAll方法。
"""
一個簡單的生產消費者模型,通過條件變數的控制產品數量的增減,調用一次生產者產品就是+1,調用一次消費者產品就會-1.
"""
"""
使用 Condition 類來完成,由於它也可以像鎖機制那樣用,所以它也有 acquire 方法和 release 方法,而且它還有
wait, notify, notifyAll 方法。
"""
import threading
import queue,time,random
class Goods:#產品類
def __init__(self):
self.count = 0
def add(self,num = 1):
self.count += num
def sub(self):
if self.count>=0:
self.count -= 1
def empty(self):
return self.count <= 0
class Procer(threading.Thread):#生產者類
def __init__(self,condition,goods,sleeptime = 1):#sleeptime=1
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime
def run(self):
cond = self.cond
goods = self.goods
while True:
cond.acquire()#鎖住資源
goods.add()
print("產品數量:",goods.count,"生產者線程")
cond.notifyAll()#喚醒所有等待的線程--》其實就是喚醒消費者進程
cond.release()#解鎖資源
time.sleep(self.sleeptime)
class Consumer(threading.Thread):#消費者類
def __init__(self,condition,goods,sleeptime = 2):#sleeptime=2
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime
def run(self):
cond = self.cond
goods = self.goods
while True:
time.sleep(self.sleeptime)
cond.acquire()#鎖住資源
while goods.empty():#如無產品則讓線程等待
cond.wait()
goods.sub()
print("產品數量:",goods.count,"消費者線程")
cond.release()#解鎖資源
g = Goods()
c = threading.Condition()
pro = Procer(c,g)
pro.start()
con = Consumer(c,g)
con.start()
同步隊列
�6�9�6�9put方法和task_done方法,queue有一個未完成任務數量num,put依次num+1,task依次num-1.任務都完成時任務結束。
import threading
import queue
import time
import random
'''
1.創建一個 Queue.Queue() 的實例,然後使用數據對它進行填充。
2.將經過填充數據的實例傳遞給線程類,後者是通過繼承 threading.Thread 的方式創建的。
3.每次從隊列中取出一個項目,並使用該線程中的數據和 run 方法以執行相應的工作。
4.在完成這項工作之後,使用 queue.task_done() 函數向任務已經完成的隊列發送一個信號。
5.對隊列執行 join 操作,實際上意味著等到隊列為空,再退出主程序。
'''
class jdThread(threading.Thread):
def __init__(self,index,queue):
threading.Thread.__init__(self)
self.index = index
self.queue = queue
def run(self):
while True:
time.sleep(1)
item = self.queue.get()
if item is None:
break
print("序號:",self.index,"任務",item,"完成")
self.queue.task_done()#task_done方法使得未完成的任務數量-1
q = queue.Queue(0)
'''
初始化函數接受一個數字來作為該隊列的容量,如果傳遞的是
一個小於等於0的數,那麼默認會認為該隊列的容量是無限的.
'''
for i in range(2):
jdThread(i,q).start()#兩個線程同時完成任務
for i in range(10):
q.put(i)#put方法使得未完成的任務數量+1
E. 在python中線程和協程的區別是什麼
在python中線程和協程的區別:1、一個線程可以擁有多個協程,這樣在python中就能使用多核CPU;2、線程是同步機制,而協程是非同步;3、 協程能保留上一次調用時的狀態,每次過程重入時,就相當於進入上一次調用的狀態。
一、首先我們來了解一下線程和協程的概念
1、線程
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。線程間通信主要通過共享內存,上下文切換很快,資源開銷較少,但相比進程不夠穩定容易丟失數據。
2、協程
協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變數,所以上下文的切換非常快。
二、協程與線程的比較
1) 一個線程可以擁有多個協程,一個進程也可以單獨擁有多個協程,這樣python中則能使用多核CPU。
2) 線程進程都是同步機制,而協程則是非同步。
3)協程能保留上一次調用時的狀態,每次過程重入時,就相當於進入上一次調用的狀態。
三、線程、協程在python中的使用
1、多線程一般是使用threading庫,完成一些IO密集型並發操作。多線程的優勢是切換快,資源消耗低,但一個線程掛掉則會影響到所有線程,所以不夠穩定。現實中使用線程池的場景會比較多,具體可參考《python線程池實現》。
2、協程一般是使用gevent庫,當然這個庫用起來比較麻煩,所以使用的並不是很多。相反,協程在tornado的運用就多得多了,使用協程讓tornado做到單線程非同步,據說還能解決C10K的問題。所以協程使用的地方最多的是在web應用上。
總結一下:
IO密集型一般使用多線程或者多進程,CPU密集型一般使用多進程,強調非阻塞非同步並發的一般都是使用協程,當然有時候也是需要多進程線程池結合的,或者是其他組合方式。
推薦課程:Python高級進階視頻教程
F. python 同步框架中使用線程池是否有意義
有
簡單地說就是作為可能是僅有的支持多線程的解釋型語言(perl的多線程是殘疾,PHP沒有多線程),Python的多線程是有compromise的,在任意時間只有一個Python解釋器在解釋Python bytecode。
如果你的代碼是CPU密集型,多個線程的代碼很有可能是線性執行的。所以這種情況下多線程是雞肋,效率可能還不如單線程因為有context switch
但是:如果你的代碼是IO密集型,多線程可以明顯提高效率。例如製作爬蟲(我就不明白為什麼Python總和爬蟲聯系在一起…不過也只想起來這個例子…),絕大多數時間爬蟲是在等待socket返回數據。這個時候C代碼里是有release GIL的,最終結果是某個線程等待IO的時候其他線程可以繼續執行。
反過來講:你就不應該用Python寫CPU密集型的代碼…效率擺在那裡…
如果確實需要在CPU密集型的代碼里用concurrent,就去用multiprocessing庫。這個庫是基於multi process實現了類multi thread的API介面,並且用pickle部分地實現了變數共享。
再加一條,如果你不知道你的代碼到底算CPU密集型還是IO密集型,教你個方法:
multiprocessing這個mole有一個mmy的sub mole,它是基於multithread實現了multiprocessing的API。
G. 關於python多線程的一些問題。
創建的子線程默認是非守護的。
非守護:當主線程結束時,子線程繼續運行,二者互不影響。
子線程是守護線程:當主線程結束時,子線程也結束(不管子線程工作有沒有完成)。
join作用是線程同步,是讓主線程等待子線程結束才結束(主線程完成工作了也不結束,阻塞等待,等子線程完成其工作才一起結束)。
相信此時你已經懂你的兩個問題了。
沒加join的時候主線程結束了,所以命令提示符>>>就出來了,可是子線程還沒結束,過了3/5秒後列印了字元串。加了join後主線程等兩個子線程都結束才一起結束,所以最後才出來>>>。
理解確實有點偏差。守護是指子線程守護著主線程,你死我也死,謂之守護。
H. 用Python中threading模塊怎麼實現線程間時鍾同步
用一個全局變數來保存這個時鍾。其實線程直接訪問這個全局的變數來獲取時鍾信息。
I. python多線程的幾種方法
Python進階(二十六)-多線程實現同步的四種方式
臨界資源即那些一次只能被一個線程訪問的資源,典型例子就是列印機,它一次只能被一個程序用來執行列印功能,因為不能多個線程同時操作,而訪問這部分資源的代碼通常稱之為臨界區。
鎖機制
threading的Lock類,用該類的acquire函數進行加鎖,用realease函數進行解鎖
import threadingimport timeclass Num:
def __init__(self):
self.num = 0
self.lock = threading.Lock() def add(self):
self.lock.acquire()#加鎖,鎖住相應的資源
self.num += 1
num = self.num
self.lock.release()#解鎖,離開該資源
return num
n = Num()class jdThread(threading.Thread):
def __init__(self,item):
threading.Thread.__init__(self)
self.item = item def run(self):
time.sleep(2)
value = n.add()#將num加1,並輸出原來的數據和+1之後的數據
print(self.item,value)for item in range(5):
t = jdThread(item)
t.start()
t.join()#使線程一個一個執行
當一個線程調用鎖的acquire()方法獲得鎖時,鎖就進入「locked」狀態。每次只有一個線程可以獲得鎖。如果此時另一個線程試圖獲得這個鎖,該線程就會變為「blocked」狀態,稱為「同步阻塞」(參見多線程的基本概念)。
直到擁有鎖的線程調用鎖的release()方法釋放鎖之後,鎖進入「unlocked」狀態。線程調度程序從處於同步阻塞狀態的線程中選擇一個來獲得鎖,並使得該線程進入運行(running)狀態。
信號量
信號量也提供acquire方法和release方法,每當調用acquire方法的時候,如果內部計數器大於0,則將其減1,如果內部計數器等於0,則會阻塞該線程,知道有線程調用了release方法將內部計數器更新到大於1位置。
import threadingimport timeclass Num:
def __init__(self):
self.num = 0
self.sem = threading.Semaphore(value = 3) #允許最多三個線程同時訪問資源
def add(self):
self.sem.acquire()#內部計數器減1
self.num += 1
num = self.num
self.sem.release()#內部計數器加1
return num
n = Num()class jdThread(threading.Thread):
def __init__(self,item):
threading.Thread.__init__(self)
self.item = item def run(self):
time.sleep(2)
value = n.add()
print(self.item,value)for item in range(100):