python进程线程协程区别_Python3多线程与协程
python中的多線程非常的常用,之前一直糊里糊涂地使用,沒有一些系統(tǒng)性的概念,記錄一下~
0x001 多線程的優(yōu)勢:可將長時間占用的程序放到后臺
可能會加速程序執(zhí)行速度
能夠?qū)崿F(xiàn)一些類似同步執(zhí)行的效果
0x002 線程線程是OS的執(zhí)行單元
每個獨立的線程都有一個程序運行的入口、順序執(zhí)行序列和程序出口,線程不能離開程序獨立執(zhí)行。
每個線程都有自己唯一的一組CPU寄存器(上下文),反映了線程上次運行時該CPU寄存器的狀態(tài)。線程中指令指針和堆棧指針寄存器非常重要,線程在進程中得到上下文,這些地址用于標(biāo)志擁有線程的進程地址空間中的內(nèi)存
線程可被搶占
線程退讓
0x01 分類:名字
說明
用戶線程
不需內(nèi)核支持而在用戶程序中實現(xiàn)的線程
內(nèi)核線程
操作系統(tǒng)內(nèi)核創(chuàng)建和撤銷
0x02 Py3中的threading模塊:方法
說明
threading.current_thread()
返回當(dāng)前的線程變量
threading.enumerate()
返回正在運行線程的list(啟動后,結(jié)束前)
threading.active_count
等于len(threading.enumerate())
提供了 Thread類,所以還可以
方法
說明
run()
表示線程活動的方法
start()
啟動線程活動
join([time])
阻塞式等待線程終止
isAlive()
線程是否活動
getName()
返回線程名
setName()
設(shè)置線程名
# -*- coding:utf-8 -*-
# 多線程
# DYBOY
# time:2019-3-10 09:37:48
import threading
import time
def printNum(endNum):
for i in range(1,endNum+1):
print(i, time.time())
# 創(chuàng)建線程
t = threading.Thread(target=printNum, name='printThread', args=(10,))
t.start()
t.join()
print("線程%s結(jié)束" % threading.current_thread().name)
0x003 多線程&多進程&線程鎖多進程中同一變量,各自有拷貝到自己的進程中,互不影響,多線程中,變量由多個線程共享,因此多線程中變量的同步就需要的到控制
lock = threading.Lock()
def runThread():
for i in range(1000):
lock.acquire()
try:
#....執(zhí)行函數(shù)
finally:
lock.release()
# -*- coding:utf-8 -*-
# 多線程
# DYBOY
# time:2019-3-10 09:37:48
import threading
import time
money = 0
lock = threading.Lock()
def chaneMoney(num):
global money
money += num
money -= num
def runThread(n):
for i in range(1000):
lock.acquire()
try:
chaneMoney(n)
finally:
lock.release()
t1 = threading.Thread(target=runThread, args=(100,))
t2 = threading.Thread(target=runThread, args=(50,))
t1.start()
t2.start()
t1.join()
t2.join()
print("余額:",money)
ps: 在實際的運行中,發(fā)現(xiàn)似乎線程鎖沒有起到作用,在線程中的join() 方法似乎是有影響的,
join():阻塞當(dāng)前進程/線程,直到調(diào)用join方法的那個進程執(zhí)行完,再繼續(xù)執(zhí)行當(dāng)前進程。相當(dāng)于線程守護,直到調(diào)用join()方法的線程執(zhí)行完畢,才將控制權(quán)交給主進程。
0x04 問題?
從上,看到多線程中為了保證數(shù)據(jù)的一致性,使用了線程鎖來實現(xiàn)類似同步的功能,然而這樣反而多了獲取鎖和釋放鎖的步驟,所以在我看來。線程也沒有加快程序的運行時間。
一個程序從執(zhí)行到結(jié)束,首先會創(chuàng)建一個主進程,os的執(zhí)行單元是線程,一個進程有至少一個或多個線程來實現(xiàn)其功能,在線程的創(chuàng)建和上下文切換是一個比較大的開銷,提升多線程的優(yōu)勢就需要從其中來考慮:
無鎖并發(fā)(減少數(shù)據(jù)關(guān)聯(lián)度,更合理優(yōu)化的實現(xiàn)方式)
減少并發(fā)(線程不能無限制的多)
減少上下文切換的開銷(協(xié)程)
0x05 協(xié)程函數(shù)調(diào)用的時候,是使用棧的方式,比如A調(diào)用B,B調(diào)用C,C執(zhí)行返回給B,B執(zhí)行完后返回給A,是一個壓棧出棧的過程
子程序(函數(shù)),總是一個入口,一次返回,調(diào)用的順序永遠(yuǎn)如此,所以如果有比較頻繁的函數(shù)調(diào)用,那么就用較多的上下文切換時間,利用協(xié)程(微線程)可以較好解決這個問題。
協(xié)程是一個線程執(zhí)行,那怎么利用多核CPU呢?最簡單的方法是多進程+協(xié)程,既充分利用多核,又充分發(fā)揮協(xié)程的高效率,可獲得極高的性能。(多進程)
# -*- coding:utf-8 -*-
# 協(xié)程 gevent
# DYBOY
# time:2019-3-10 09:37:48
# description: 下載圖片到本地(普通版本)
# from gevent import monkey
# monkey.patch_all()
import requests,time,json
def get_save_pic(picUrl, name):
img = requests.get(picUrl)
with open('pic/'+name,'wb') as f:
f.write(img.content)
return None
if __name__ == '__main__':
sT = time.time()
jsonData = requests.get('http://img.top15.cn/piclist.php')
jsonData = json.loads(jsonData.text)
imgs = jsonData['data']
for img in imgs:
get_save_pic(img[0], img[1])
print("Success", time.time() - sT)
網(wǎng)絡(luò)效果好的時候:
# -*- coding:utf-8 -*-
# 協(xié)程 gevent
# DYBOY
# time:2019-3-10 09:37:48
# description: 下載圖片到本地
from gevent import monkey
monkey.patch_all()
import gevent,requests,time,json
def get_save_pic(picUrl, name):
img = requests.get(picUrl)
with open('pic/'+name,'wb') as f:
f.write(img.content)
return None
if __name__ == '__main__':
startTime = time.time()
jsonData = requests.get('http://img.top15.cn/piclist.php')
jsonData = json.loads(jsonData.text)
imgs = jsonData['data']
targetLists = []
for img in imgs:
targetLists.append(gevent.spawn(get_save_pic, img[0], img[1]))
gevent.joinall(targetLists)
print("Success!", time.time()-startTime)
# 不知道什么原因,沒有輸出,但是從執(zhí)行的結(jié)果上來看
# 最后,所有圖片同時在文件夾生成,非常迅速
2019-3-10 22:05:04 在命令行下可正常執(zhí)行!
從肉眼可見的角度來看,還是協(xié)程的效果更好(在數(shù)據(jù)量不大下,感覺比較而得出的結(jié)論還是不是很有說服力,在數(shù)據(jù)量大的情況下,線程不能無限增加,協(xié)程的效果表現(xiàn)更優(yōu)異,再加上多進程應(yīng)該就更NICE了)。
0x06 總結(jié)
本次探究的是多線程與協(xié)程的區(qū)別,多線程不能無限創(chuàng)建,所以有的時候創(chuàng)建多線程在生產(chǎn)環(huán)境下是不可行的,在爬蟲下載圖片這部分是可以使用多線程去下載,多線程其實也是一個等待執(zhí)行的過程,其與協(xié)程的差別主要是在上下文切換上,協(xié)程減少了上下文切換的時間,是程序自己控制的,而多線程的上下文切換是需要系統(tǒng)調(diào)用會耗費更多的時間,本次例子實現(xiàn)中使用了monkey這個模塊,還不清楚其中遇到的輸出問題,繼續(xù)探究!
總結(jié)
以上是生活随笔為你收集整理的python进程线程协程区别_Python3多线程与协程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql udf提权_MySQL日志安
- 下一篇: python定义私有变量的方法_Pyth