1. 程式人生 > >python:多進程、多線程

python:多進程、多線程

sts test app 復雜 全局 進行 span 函數 join方法


線程&進程
對於操作系統來說,一個任務就是一個進程(Process),比如打開一個瀏覽器就是啟動一個瀏覽器進程,打開一個記事本就啟動了一個記事本進程,打開兩個記事本就啟動了兩個記事本進程,打開一個Word
就啟動了一個Word進程。進程是很多資源的集合。
有些進程還不止同時幹一件事,比如Word,它可以同時進行打字、拼寫檢查、打印等事情。在一個進程內部,要同時幹多件事,就需要同時運行多個“子任務”,我們把進程內的這些“子任務”稱為線程(Thread
)。
由於每個進程至少要幹一件事,所以,一個進程至少有一個線程。當然,像Word這種復雜的進程可以有多個線程,多個線程可以同時執行,多線程的執行方式和多進程是一樣的,也是由操作系統在多個線程之間
快速切換,讓每個線程都短暫地交替運行,看起來就像同時執行一樣。當然,真正地同時執行多線程需要多核CPU才可能實現。線程是最小的執行單元,而進程由至少一個線程組成。
我們在做事情的時候,一個人做是比較慢的,如果多個人一起來做的話,就比較快了,程序也是一樣的,我們想運行的速度快一點的話,就得使用多進程,或者多線程,在python裏面,多線程被很多人詬病,為
什麽呢,因為Python的解釋器使用了GIL的一個叫全局解釋器鎖,它不能利用多核CPU,只能運行在一個cpu上面,但是你在運行程序的時候,看起來好像還是在一起運行的,是因為操作系統輪流讓各個任務交替
執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反復執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像
所有任務都在同時執行一樣。這個叫做上下文切換。
多線程:

多線程要用到threading這個模塊
eg1:
import threading,time
def run(count):
time.sleep(2)
print(count)
start=time.time()
threads=[]
for i in range(5):
t=threading.Thread(target=run,args=(i,))
#創建一個線程,指定它運行哪個函數;args=(i,)是run函數的入參,一個參數要加逗號,沒有參數就不寫args
#如果不加線程,這段代碼運行需要10秒,加了線程時間就減少很多
t.start()
threads.append(t)
#把啟動的每一個線程添加到這個線程組裏面

for th in threads:
th.join() #th代表的是每個子線程,join方法是等待子線程結束的意思,子線程結束了才繼續往下走;
#如果沒有join的話,就是主線程和子線程同時執行,子線程因為要sleep兩秒,所以主線程先走完,然後子線程走完
end=time.time()
print(‘總共運行了‘,end-start)
在運行python文件時,如果你不啟動多線程,那最少有一個線程在運行
線程之間是相互獨立的,都是同時執行,互相沒有關系
程序開始運行的時候的線程是主線程,主線程先走,並不是等其他線程走完它再走
通過多線程去調用一個函數的時候,是沒有辦法獲取到這個函數的返回值的;如果多線程想獲取返回結果,可以把返回值放添加到列表裏
上面的例子,線程有6個

設置守護線程:

for i in range(5):
t=threading.Tread(target=run,args(i,))
t.setDarmon(True)
#把子線程設置成守護線程
#主線程只要一結束,子線程都得結束,有沒有執行完都得結束
t.start()
print(‘over‘)


線程鎖
線程鎖就是,很多線程一起在操作一個數據的時候,可能會有問題,就要把這個數據加個鎖,同一時間只能有一個線程操作這個數據。
from threading import Lock
num=0
lock=Lock() #申請一把鎖
def run2():
global num
lock.acquire #加鎖
num+=1
lock.release() #解鎖
lis=[]
for i in range(5):
t=threading.Thread(target=run2)
t.start()
lis.append(t)
for t in lis:
t.join()
print(‘over‘,num)

下面來個簡單的爬蟲,看下
多線程的效果:
import threading
import requests, time

urls = {
"baidu": ‘http://www.baidu.com‘,
"blog": ‘http://www.nnzhp.cn‘,
"besttest": ‘http://www.besttest.cn‘,
"taobao": "http://www.taobao.com",
"jd": "http://www.jd.com",
}

def run(name, url):
res = requests.get(url)
with open(name + ‘.html‘, ‘w‘, encoding=res.encoding) as fw:
fw.write(res.text)
#把網站上的html內容下載到文件裏
start_time = time.time()
lis = []
for url in urls:
t = threading.Thread(target=run, args=(url, urls[url]))
t.start()
lis.append(t)
for t in lis:
t.join() #下載html內容的子線程結束之後再走這裏
end_time = time.time()
print(‘run time is %s‘ % (end_time - start_time))

# 下面是單線程的執行時間
# start_time = time.time()
# for url in urls:
# run(url,urls[url])
# end_time = time.time()
# print(‘run time is %s‘%(end_time-start_time))

多進程:
python裏面的多線程是利用不了多核cpu的
多進程是可以利用多核cpu的,python中多進程使用multiprocessing模塊
from multiprocessing import Process
import time
def f(name):
time.sleep(2)
print(‘hello‘, name)
ps=[]
for i in range(5):
p = Process(target=f, args=(‘niu‘,))
p.start()
ps.append(p)
for p in ps:
p.join()
#多線程和多進程語法一樣
#多進程適用於cpu密集型任務,即操作cpu比較多的
#多線程適用於io密集型任務,即操作input/output比較多的,比如操作磁盤

python:多進程、多線程