進程:進程是一個具有獨立功能的程序關於某個數據集合的一次運行活動。進程是操作系統動態執行的基本單元。
線程:一個進程中包含若干線程,當然至少有一個線程,線程可以利用進程所擁有的資源。線程是獨立運行和獨立調度的基本單元。
協程:協程是一種用戶態的輕量級線程。協程無需線程上下文切換的開銷,也無需原子操作鎖定及同步的開銷。
同步:不同程序單元為了完成某個任務,在執行過程中需靠某種通信方式以協調一致,稱這些程序單元是同步執行的。
異步:為完成某個任務,不同程序單元之間過程中無需通信協調,也能完成任務的方式,不相關的程序單元之間可以是異步的。
多進程:多進程就是利用 CPU 的多核優勢,在同一時間並行地執行多個任務。多進程模式優點就是穩定性高,因為一個子進程崩潰了,不會影響主進程和其他子進程,但是操作系統能同時運行的進程數是有限的。
多線程:多線程模式通常比多進程快一點,但是也快不到哪去,而且,多線程模式致命的缺點就是任何一個線程掛掉都可能直接造成整個進程崩潰,因為所有線程共享進程的內存。
簡單示例
# encoding=utf-8
import asyncio
import time
import multiprocessing, threading
def func(index):
# print("start ", index)
time.sleep(5)
# print("end ", index)
async def funct(index):
# print("start ", index)
await asyncio.sleep(5)
# print("end ", index)
if __name__ == "__main__":
# 任務數
r = 50
# process
print("process test")
start = time.time()
p_list = []
for i in range(r):
p = multiprocessing.Process(target=func, args=(i, ))
p.start()
p_list.append(p)
for i in p_list:
i.join()
print("process time ", time.time() - start)
# thread
print("thread test")
start = time.time()
p_list = []
for i in range(r):
p = threading.Thread(target=func, args=(i, ))
p.start()
p_list.append(p)
for i in p_list:
i.join()
print("thread time ", time.time() - start)
# async
print("async test")
start = time.time()
p_list = [funct(i) for i in range(r)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*p_list))
print("async time ", time.time() - start)
簡單睡眠5秒模擬任務,執行50個任務,我們先來看下效果
process test process time 6.950000047683716 thread test thread time 5.016000032424927 async test async time 5.005999803543091
協程跟多線程差不多,多進程就比較慢了,不過多進程是適合CPU密集型的,對於I/O密集型的還是最適合的是協程,相對多線程,兩者性能相當,但是協程內存消耗小,且不需要切換線程的開銷,因為只一個線程中執行任務
I/O示例
上面任務設計的比較挫,下面改一下,改成I/O型的,這里多進程就不比較了,肯定慢很多的
# encoding=utf-8
import asyncio
import functools
import time
import multiprocessing, threading
import aiohttp
import requests
headers = {
'Host': 'movie.douban.com',
'Referer': 'https://movie.douban.com/top250?start=225&filter=',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
}
def func(index):
# print("start ", index)
resp = requests.get("https://movie.douban.com/top250?start=0")
# time.sleep(5)
# print("end ", index)
async def funct(index):
# print("start ", index)
# resp = await asyncio._get_running_loop().run_in_executor(None,
# functools.partial(requests.get,
# allow_redirects=False,
# headers=headers),
# "https://movie.douban.com/top250?start=0")
async with aiohttp.ClientSession() as session:
async with session.get("https://movie.douban.com/top250?start=0", timeout=5) as resp:
pass
# await asyncio.sleep(5)
# print("end ", index)
if __name__ == "__main__":
# 任務數
r = 50
# thread
print("thread test")
start = time.time()
p_list = []
for i in range(r):
p = threading.Thread(target=func, args=(i, ))
p.start()
p_list.append(p)
for i in p_list:
i.join()
print("thread time ", time.time() - start)
# async
print("async test")
start = time.time()
p_list = [funct(i) for i in range(r)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*p_list))
print("async time ", time.time() - start)
執行結果如下
thread test thread time 0.8309998512268066 async test async time 0.7860002517700195
協程快那么一點,協程函數中發請求是使用的aiohttp,沒有使用requests,因為不支持異步,requests是同步的,換成requests的話會慢很多,而aiohttp是根據協程而設計的
thread test thread time 0.8390002250671387 async test async time 1.066999912261963
