❶ python 多線程為什麼沒有並行
1. GIL是什麼?
GIL的全稱是Global Interpreter Lock(全局解釋器鎖),來源是python設計之初的考慮,為了數據安全所做的決定。
2. 每個CPU在同一時間只能執行一個線程
在單核CPU下的多線程其實都只是並發,不是並行,並發和並行從宏觀上來講都是同時處理多路請求的概念。但並發和並行又有區別,並行是指兩個或者多個事件在同一時刻發生;而並發是指兩個或多個事件在同一時間間隔內發生。
❷ Python多線程總結
在實際處理數據時,因系統內存有限,我們不可能一次把所有數據都導出進行操作,所以需要批量導出依次操作。為了加快運行,我們會採用多線程的方法進行數據處理, 以下為我總結的多線程批量處理數據的模板:
主要分為三大部分:
共分4部分對多線程的內容進行總結。
先為大家介紹線程的相關概念:
在飛車程序中,如果沒有多線程,我們就不能一邊聽歌一邊玩飛車,聽歌與玩 游戲 不能並行;在使用多線程後,我們就可以在玩 游戲 的同時聽背景音樂。在這個例子中啟動飛車程序就是一個進程,玩 游戲 和聽音樂是兩個線程。
Python 提供了 threading 模塊來實現多線程:
因為新建線程系統需要分配資源、終止線程系統需要回收資源,所以如果可以重用線程,則可以減去新建/終止的開銷以提升性能。同時,使用線程池的語法比自己新建線程執行線程更加簡潔。
Python 為我們提供了 ThreadPoolExecutor 來實現線程池,此線程池默認子線程守護。它的適應場景為突發性大量請求或需要大量線程完成任務,但實際任務處理時間較短。
其中 max_workers 為線程池中的線程個數,常用的遍歷方法有 map 和 submit+as_completed 。根據業務場景的不同,若我們需要輸出結果按遍歷順序返回,我們就用 map 方法,若想誰先完成就返回誰,我們就用 submit+as_complete 方法。
我們把一個時間段內只允許一個線程使用的資源稱為臨界資源,對臨界資源的訪問,必須互斥的進行。互斥,也稱間接制約關系。線程互斥指當一個線程訪問某臨界資源時,另一個想要訪問該臨界資源的線程必須等待。當前訪問臨界資源的線程訪問結束,釋放該資源之後,另一個線程才能去訪問臨界資源。鎖的功能就是實現線程互斥。
我把線程互斥比作廁所包間上大號的過程,因為包間里只有一個坑,所以只允許一個人進行大號。當第一個人要上廁所時,會將門上上鎖,這時如果第二個人也想大號,那就必須等第一個人上完,將鎖解開後才能進行,在這期間第二個人就只能在門外等著。這個過程與代碼中使用鎖的原理如出一轍,這里的坑就是臨界資源。 Python 的 threading 模塊引入了鎖。 threading 模塊提供了 Lock 類,它有如下方法加鎖和釋放鎖:
我們會發現這個程序只會列印「第一道鎖」,而且程序既沒有終止,也沒有繼續運行。這是因為 Lock 鎖在同一線程內第一次加鎖之後還沒有釋放時,就進行了第二次 acquire 請求,導致無法執行 release ,所以鎖永遠無法釋放,這就是死鎖。如果我們使用 RLock 就能正常運行,不會發生死鎖的狀態。
在主線程中定義 Lock 鎖,然後上鎖,再創建一個子 線程t 運行 main 函數釋放鎖,結果正常輸出,說明主線程上的鎖,可由子線程解鎖。
如果把上面的鎖改為 RLock 則報錯。在實際中設計程序時,我們會將每個功能分別封裝成一個函數,每個函數中都可能會有臨界區域,所以就需要用到 RLock 。
一句話總結就是 Lock 不能套娃, RLock 可以套娃; Lock 可以由其他線程中的鎖進行操作, RLock 只能由本線程進行操作。
❸ python多線程並行計算通過向線程池ThreadPoolExecutor提交任務的實現方法
Python的線程池可以有效地控制系統中並發線程的數量。
當程序中需要創建許多生存期較短的線程執行運算任務時,首先考慮使用線程池。線程池任務啟動時會創建出最大線程數參數 max_workers 指定數量的空閑線程,程序只要將執行函數提交給線程池,線程池就會啟動一個空閑的線程來執行它。當該函數執行結束後,該線程並不會死亡,而是再次返回到線程池中變成空閑狀態,等待執行下一個函數。配合使用 with 關鍵字實現任務隊列完成後自動關閉線程池釋放資源。
❹ python多進程,多線程分別是並行還是並發
並發和並行
你吃飯吃到一半,電話來了,你一直到吃完了以後才去接,這就說明你不支持並發也不支持並行。
你吃飯吃到一半,電話來了,你停了下來接了電話,接完後繼續吃飯,這說明你支持並發。
你吃飯吃到一半,電話來了,你一邊打電話一邊吃飯,這說明你支持並行。
並發的關鍵是你有處理多個任務的能力,不一定要同時。
並行的關鍵是你有同時處理多個任務的能力。
所以我認為它們最關鍵的點就是:是否是『同時』。
Python 中沒有真正的並行,只有並發
無論你的機器有多少個CPU, 同一時間只有一個Python解析器執行。這也和大部分解釋型語言一致, 都不支持並行。這應該是python設計的先天缺陷。
javascript也是相同的道理, javascript早起的版本只支持單任務,後來通過worker來支持並發。
Python中的多線程
先復習一下進程和線程的概念
所謂進程,簡單的說就是一段程序的動態執行過程,是系統進行資源分配和調度的一個基本單位。一個進程中又可以包含若干個獨立的執行流,我們將這些執行流稱為線程,線程是CPU調度和分配的基本單位。同一個進程的線程都有自己的專有寄存器,但內存等資源是共享的。
這里有一個更加形象的解釋, 出自阮一峰大神的傑作:
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
Python中的thread的使用
通過 thread.start_new_thread 方法
import thread
import time
# Define a function for the thread
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print "%s: %s" % ( threadName, time.ctime(time.time()) )
# Create two threads as follows
try:
thread.start_new_thread( print_time, ("Thread-1", 2, ) )
thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print "Error: unable to start thread"
while 1:
pass
通過繼承thread
#!/usr/bin/python
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
print_time(self.name, self.counter, 5)
print "Exiting " + self.name
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
print "Exiting Main Thread"
線程的同步
#!/usr/bin/python
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
# Get lock to synchronize threads
threadLock.acquire()
print_time(self.name, self.counter, 3)
# Free lock to release next thread
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
threadLock = threading.Lock()
threads = []
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
# Add threads to thread list
threads.append(thread1)
threads.append(thread2)
# Wait for all threads to complete
for t in threads:
t.join()
print "Exiting Main Thread"
利用multiprocessing多進程實現並行
進程的創建
Python 中有一套類似多線程API 的的類來進行多進程開發: multiprocessing
這里是一個來自官方文檔的例子:
from multiprocessing import Process
def f(name):
print 'hello', name
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()
類似與線程,一可以通過繼承process類來實現:
from multiprocessing import Process
class Worker(Process):
def run(self):
print("in" + self.name)
if __name__ == '__main__':
jobs = []
for i in range(5):
p = Worker()
jobs.append(p)
p.start()
for j in jobs:
j.join()
進程的通信
Pipe()
pipe()函數返回一對由雙向通信的管道連接的對象,這兩個對象通過send, recv 方法實現 信息的傳遞
from multiprocessing import Process, Pipe
def f(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print parent_conn.recv() # prints "[42, None, 'hello']"
p.join()
Quene
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print q.get() # prints "[42, None, 'hello']"
p.join()
進程間的同步
Python 中多進程中也有類似線程鎖的概念,使用方式幾乎一樣:
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
print 'hello world', i
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(10):
Process(target=f, args=(lock, num)).start()
進程間的共享內存
每個進程都有獨自的內存,是不能相互訪問的, 也行 python官方覺得通過進程通信的方式過於麻煩,提出了共享內存的概念,以下是官方給出的例子:
from multiprocessing import Process, Value, Array
def f(n, a):
n.value = 3.1415927
for i in range(len(a)):
a[i] = -a[i]
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
p.start()
p.join()
print num.value
print arr[:]
總結
python通過多進程實現多並行,充分利用多處理器,彌補了語言層面不支持多並行的缺點。Python, Node.js等解釋型語言似乎都是通過這種方式來解決同一個時間,一個解釋器只能處理一段程序的問題, 十分巧妙。
❺ python怎麼能同時執行代碼(多線程)
import_thread # 引入線程包
# 1. 定義線程
def 線程1名字():
# 在這個地方寫線程1要幹嘛......
def 線程2名字():
# 在這個地方寫線程2要幹嘛......
def 線程3名字():
# 在這個地方寫線程3要幹嘛......
# 以此類推....
# 2. 啟動這些線程
_thread.start_new_thread(線程1名字,())
_thread.start_new_thread(線程2名字,())
_thread.start_new_thread(線程3名字,())
# 以此類推....
# 啟動之後這些線程都是同時執行的
# 如果某個線程函數有參數需要傳入,可使用:
_thread.start_new_thread(某線程名字,(參數1,參數2...) )
❻ Python 的多線程問題。。
python 的GIL規定每個時刻只能有一個線程訪問python虛擬機,所以你要用python的多線程來做計算是很不合算的,但是對於IO密集型的應用,例如網路交互來說,python的多線程還是非常給力的。
如果你是一個計算密集型的任務,非要用python來並行執行的話,有以下幾個方法:
1 使用python的multiprocessing 模塊,能夠發揮多核的優勢。
2 使用ironPython,但是這個只能在windows下用
3 使用pypy,這個可以實現真正的多線程。
❼ python多線程並發數量控制
python多線程如果不進行並發數量控制,在啟動線程數量多到一定程度後,會造成線程無法啟動的錯誤。
控制多線程並發數量的方法有好幾鍾,下面介紹用queue控制多線程並發數量的方法。python3
❽ python之多線程
進程的概念:以一個整體的形式暴露給操作系統管理,裡麵包含各種資源的調用。 對各種資源管理的集合就可以稱為進程。
線程的概念:是操作系統能夠進行運算調度的最小單位。本質上就是一串指令的集合。
進程和線程的區別:
1、線程共享內存空間,進程有獨立的內存空間。
2、線程啟動速度快,進程啟動速度慢。注意:二者的運行速度是無法比較的。
3、線程是執行的指令集,進程是資源的集合
4、兩個子進程之間數據不共享,完全獨立。同一個進程下的線程共享同一份數據。
5、創建新的線程很簡單,創建新的進程需要對他的父進程進行一次克隆。
6、一個線程可以操作(控制)同一進程里的其他線程,但是進程只能操作子進程
7、同一個進程的線程可以直接交流,兩個進程想要通信,必須通過一個中間代理來實現。
8、對於線程的修改,可能會影響到其他線程的行為。但是對於父進程的修改不會影響到子進程。
第一個程序,使用循環來創建線程,但是這個程序中一共有51個線程,我們創建了50個線程,但是還有一個程序本身的線程,是主線程。這51個線程是並行的。注意:這個程序中是主線程啟動了子線程。
相比上個程序,這個程序多了一步計算時間,但是我們觀察結果會發現,程序顯示的執行時間只有0.007秒,這是因為最後一個print函數它存在於主線程,而整個程序主線程和所有子線程是並行的,那麼可想而知,在子線程還沒有執行完畢的時候print函數就已經執行了,總的來說,這個時間只是執行了一個線程也就是主線程所用的時間。
接下來這個程序,吸取了上面這個程序的缺點,創建了一個列表,把所有的線程實例都存進去,然後使用一個for循環依次對線程實例調用join方法,這樣就可以使得主線程等待所創建的所有子線程執行完畢才能往下走。 注意實驗結果:和兩個線程的結果都是兩秒多一點
注意觀察實驗結果,並沒有執行列印task has done,並且程序執行時間極其短。
這是因為在主線程啟動子線程前把子線程設置為守護線程。
只要主線程執行完畢,不管子線程是否執行完畢,就結束。但是會等待非守護線程執行完畢
主線程退出,守護線程全部強制退出。皇帝死了,僕人也跟著殉葬
應用的場景 : socket-server
注意:gil只是為了減低程序開發復雜度。但是在2.幾的版本上,需要加用戶態的鎖(gil的缺陷)而在3點幾的版本上,加鎖不加鎖都一樣。
下面這個程序是一個典型的生產者消費者模型。
生產者消費者模型是經典的在開發架構中使用的模型
運維中的集群就是生產者消費者模型,生活中很多都是
那麼,多線程的使用場景是什麼?
python中的多線程實質上是對上下文的不斷切換,可以說是假的多線程。而我們知道,io操作不佔用cpu,計算佔用cpu,那麼python的多線程適合io操作密集的任務,比如socket-server,那麼cpu密集型的任務,python怎麼處理?python可以折中的利用計算機的多核:啟動八個進程,每個進程有一個線程。這樣就可以利用多進程解決多核問題。
❾ python 怎麼實現多線程的
線程也就是輕量級的進程,多線程允許一次執行多個線程,Python是多線程語言,它有一個多線程包,GIL也就是全局解釋器鎖,以確保一次執行單個線程,一個線程保存GIL並在將其傳遞給下一個線程之前執行一些操作,也就產生了並行執行的錯覺。