『壹』 為什麼有人說 python 的多線程是雞肋
因為 Python 中臭名昭著的 GIL。
那麼 GIL 是什麼?為什麼會有 GIL?多線程真的是雞肋嗎? GIL 可以去掉嗎?帶著這些問題,我們一起往下看,同時需要你有一點點耐心。
多線程是不是雞肋,我們先做個實驗,實驗非常簡單,就是將數字 「1億」 遞減,減到 0 程序就終止,這個任務如果我們使用單線程來執行,完成時間會是多少?使用多線程又會是多少?show me the code
那麼把 GIL 去掉可行嗎?
還真有人這么干多,但是結果令人失望,在1999年Greg Stein 和Mark Hammond 兩位哥們就創建了一個去掉 GIL 的 Python 分支,在所有可變數據結構上把 GIL 替換為更為細粒度的鎖。然而,做過了基準測試之後,去掉GIL的 Python 在單線程條件下執行效率將近慢了2倍。
Python之父表示:基於以上的考慮,去掉GIL沒有太大的價值而不必花太多精力。
『貳』 python 多個用戶對FTP上同一個文件做讀寫
你的意思是, 用戶用你的代碼來訪問文件? 你可以調用系統的介面來查看是否有人在使用文件; 或者在上下文管理器中加個鎖(只是個標記), 訪問的時候在旁邊隨便建個文件, 其他人看到文件存在就給個提示並退出. 讀寫完後刪除這個隨便的文件.
『叄』 python 多進程和多線程配合
由於python的多線程中存在PIL鎖,因此python的多線程不能利用多核,那麼,由於現在的計算機是多核的,就不能充分利用計算機的多核資源。但是python中的多進程是可以跑在不同的cpu上的。因此,嘗試了多進程+多線程的方式,來做一個任務。比如:從中科大的鏡像源中下載多個rpm包。
#!/usr/bin/pythonimport reimport commandsimport timeimport multiprocessingimport threadingdef download_image(url):
print '*****the %s rpm begin to download *******' % url
commands.getoutput('wget %s' % url)def get_rpm_url_list(url):
commands.getoutput('wget %s' % url)
rpm_info_str = open('index.html').read()
regu_mate = '(?<=<a href=")(.*?)(?=">)'
rpm_list = re.findall(regu_mate, rpm_info_str)
rpm_url_list = [url + rpm_name for rpm_name in rpm_list] print 'the count of rpm list is: ', len(rpm_url_list) return rpm_url_
def multi_thread(rpm_url_list):
threads = [] # url = 'https://mirrors.ustc.e.cn/centos/7/os/x86_64/Packages/'
# rpm_url_list = get_rpm_url_list(url)
for index in range(len(rpm_url_list)): print 'rpm_url is:', rpm_url_list[index]
one_thread = threading.Thread(target=download_image, args=(rpm_url_list[index],))
threads.append(one_thread)
thread_num = 5 # set threading pool, you have put 4 threads in it
while 1:
count = min(thread_num, len(threads)) print '**********count*********', count ###25,25,...6707%25
res = [] for index in range(count):
x = threads.pop()
res.append(x) for thread_index in res:
thread_index.start() for j in res:
j.join() if not threads:
def multi_process(rpm_url_list):
# process num at the same time is 4
process = []
rpm_url_group_0 = []
rpm_url_group_1 = []
rpm_url_group_2 = []
rpm_url_group_3 = [] for index in range(len(rpm_url_list)): if index % 4 == 0:
rpm_url_group_0.append(rpm_url_list[index]) elif index % 4 == 1:
rpm_url_group_1.append(rpm_url_list[index]) elif index % 4 == 2:
rpm_url_group_2.append(rpm_url_list[index]) elif index % 4 == 3:
rpm_url_group_3.append(rpm_url_list[index])
rpm_url_groups = [rpm_url_group_0, rpm_url_group_1, rpm_url_group_2, rpm_url_group_3] for each_rpm_group in rpm_url_groups:
each_process = multiprocessing.Process(target = multi_thread, args = (each_rpm_group,))
process.append(each_process) for one_process in process:
one_process.start() for one_process in process:
one_process.join()# for each_url in rpm_url_list:# print '*****the %s rpm begin to download *******' %each_url## commands.getoutput('wget %s' %each_url)
def main():
url = 'https://mirrors.ustc.e.cn/centos/7/os/x86_64/Packages/'
url_paas = 'http://mirrors.ustc.e.cn/centos/7.3.1611/paas/x86_64/openshift-origin/'
url_paas2 ='http://mirrors.ustc.e.cn/fedora/development/26/Server/x86_64/os/Packages/u/'
start_time = time.time()
rpm_list = get_rpm_url_list(url_paas) print multi_process(rpm_list) # print multi_thread(rpm_list)
#print multi_process()
# print multi_thread(rpm_list)
# for index in range(len(rpm_list)):
# print 'rpm_url is:', rpm_list[index]
end_time = time.time() print 'the download time is:', end_time - start_timeprint main()123456789101112131415161718
代碼的功能主要是這樣的:
main()方法中調用get_rpm_url_list(base_url)方法,獲取要下載的每個rpm包的具體的url地址。其中base_url即中科大基礎的鏡像源的地址,比如:http://mirrors.ustc.e.cn/centos/7.3.1611/paas/x86_64/openshift-origin/,這個地址下有幾十個rpm包,get_rpm_url_list方法將每個rpm包的url地址拼出來並返回。
multi_process(rpm_url_list)啟動多進程方法,在該方法中,會調用多線程方法。該方法啟動4個多進程,將上面方法得到的rpm包的url地址進行分組,分成4組,然後每一個組中的rpm包再最後由不同的線程去執行。從而達到了多進程+多線程的配合使用。
代碼還有需要改進的地方,比如多進程啟動的進程個數和rpm包的url地址分組是硬編碼,這個還需要改進,畢竟,不同的機器,適合同時啟動的進程個數是不同的。
『肆』 python 怎麼實現多線程的
線程也就是輕量級的進程,多線程允許一次執行多個線程,Python是多線程語言,它有一個多線程包,GIL也就是全局解釋器鎖,以確保一次執行單個線程,一個線程保存GIL並在將其傳遞給下一個線程之前執行一些操作,也就產生了並行執行的錯覺。
『伍』 請教python如何開啟多線程
可以定義函數把這些代碼放在不同的函數里,然後threading模塊
import threading
th1 = threading.Thread(target=func1, args=(arg1, arg2, ...))
照這樣再定義別的線程,開啟用Thread類的start方法
th1.start(); th2.start(); ...
『陸』 python多線程中每個線程如果不加休眠時間就會只泡在一個線程上,這該如何處理謝謝
這是三個線程都在跑啊,只是並發的而已
『柒』 python py文件同時開兩個線程可以嗎
可以的。
Python 多線程
多線程類似於同時執行多個不同程序,多線程運行有如下優點:
使用線程可以把占據長時間的程序中的任務放到後台去處理。
用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
程序的運行速度可能加快
在一些等待的任務實現上如用戶輸入、文件讀寫和網路收發數據等,線程就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如內存佔用等等。
線程在執行過程中與進程還是有區別的。每個獨立的進程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
每個線程都有他自己的一組CPU寄存器,稱為線程的上下文,該上下文反映了線程上次運行該線程的CPU寄存器的狀態。
指令指針和堆棧指針寄存器是線程上下文中兩個最重要的寄存器,線程總是在進程得到上下文中運行的,這些地址都用於標志擁有線程的進程地址空間中的內存。
線程可以被搶占(中斷)。
在其他線程正在運行時,線程可以暫時擱置(也稱為睡眠) -- 這就是線程的退讓。
『捌』 為什麼有人說 Python 的多線程是雞肋呢
由於python是一種解釋性腳本語言,因此運行過程中始終存在全局線程鎖。
簡單的來說就是在實際的運行過程中,python只能利用一個線程,因此python的多線程並不達到C語言多線程的性能。
建議使用多進程來代替多線程,但需要注意的是多進程最好不要涉及到例如文件操作的頻繁操作IO的功能。
『玖』 Python多線程是什麼意思
簡單地說就是作為可能是僅有的支持多線程的解釋型語言(perl的多線程是殘疾,PHP沒有多線程),Python的多線程是有compromise的,在任意時間只有一個Python解釋器在解釋Python bytecode。
UPDATE:如評論指出,Ruby也是有thread支持的,而且至少Ruby MRI是有GIL的。
如果你的代碼是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。
假設你使用的是multiprocessing的Pool,是使用多進程實現了concurrency
from multiprocessing import Pool
如果把這個代碼改成下面這樣,就變成多線程實現concurrency
from multiprocessing.mmy import Pool
兩種方式都跑一下,哪個速度快用哪個就行了。
UPDATE:
剛剛才發現concurrent.futures這個東西,包含ThreadPoolExecutor和ProcessPoolExecutor,可能比multiprocessing更簡單