Python全域性直譯器鎖GIL與多執行緒

2021-10-07 08:46:03 字數 4391 閱讀 8070

python中如果是 i/o密集型的操作,用多執行緒(協程asyncio、執行緒threading),如果i/o操作很慢,需要很多任務/執行緒協同操作,用asyncio,如果需要有限數量的任務/執行緒,那麼使用多執行緒。

如果是cpu密集型操作,用多程序(multeprocessing)。

設計者為了規避類似記憶體管理這樣的複雜競爭風險問題(race condition);

cpython大量使用c語言庫,但大部分c語言庫都不是執行緒安全的(執行緒安全會降低效能和增加複雜度)。

繞過cpython,使用jpython等別的實現;

把關鍵效能**放到其他語言中實現,比如c++

asyncio包含有協程需要的所有魔法

asyncio 和其他 python 程式一樣,是單執行緒的,它只有乙個主線程event loop,但是可以進行多個不同的任務(task),這裡的任務,就是特殊的 future 物件。這些不同的任務,被乙個叫做 event loop 的物件所控制。

當在 jupyter 中執行: %time asyncio.run(main([『url_1』, 『url_2』, 『url_3』,

『url_4』]))

出現報錯: runtimeerror: asyncio.run() cannot be called from a running event loop原因是: the problem in your case is that jupyter (ipython)

is already running an event loop (for ipython ≥ 7.0) 解決是: 將 %time

asyncio.run(main([『url_1』, 『url_2』, 『url_3』, 『url_4』])) 換成 await

main([『url_1』, 『url_2』, 『url_3』, 『url_4』])

# 協程 

import asyncio

async

defcrawl_page

(url)

:print

('crawling {}'

.format

(url)

) sleep_time =

int(url.split(

'_')[-

1])await asyncio.sleep(sleep_time)

print

('ok {}'

.format

(url)

)async

defmain

(urls)

: tasks =

[asyncio.create_task(crawl_page(url)

)for url in urls]

for task in tasks:

await task

# %time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))

await main(

['url_1'

,'url_2'

,'url_3'

,'url_4'

])

結果如下圖:

threading

threadingpool

# 非同步程式設計

from threading import thread

import time

import functools

# 裝飾器實現耗時記錄

deflog_execution_time

(func)

: @functools.wraps(func)

def(

*args,

**kwargs)

: start = time.perf_counter(

) res = func(

*args,

**kwargs)

end = time.perf_counter(

)print

('{} took {} s'

.format

(func.__name__,

(end - start)))

return res

@log_execution_time

defcountdown

(n):

while n >0:

n -=

1n =

100000000

t1 = thread(target=countdown, args=

[n //2]

)t2 = thread(target=countdown, args=

[n //2]

)t1.start(

)t2.start(

)t1.join(

)t2.join(

)

等待執行結束並返回結果

import concurrent.futures

import requests

import time

defdownload_one

(url)

: resp = requests.get(url)

# print('read {} from {}'.format(len(resp.content), url))

return

('read {} from {}'

.format

(len

(resp.content)

, url)

)def

download_all

(sites)

:with concurrent.futures.threadpoolexecutor(max_workers=5)

as executor:

# executor.map(download_one,sites)

to_do =

for site in sites:

future = executor.submit(download_one, site)

for future in to_do:

future.add_done_callback(

lambda future:

print

(future.result())

)def

main()

: sites =

['',''

,'',''

,'',''

,'',''

] start_time = time.perf_counter(

) download_all(sites)

end_time = time.perf_counter(

)print

('download {} sites in {} seconds'

.format

(len

(sites)

, end_time - start_time)

)if __name__ ==

'__main__'

: main(

)

import multiprocessing

import time

defcpu_bound

(number)

:print

(number)

return

sum(i * i for i in

range

(number)

)def

find_sums

(numbers)

:with multiprocessing.pool(

)as pool:

pool.

map(cpu_bound, numbers)

if __name__ ==

"__main__"

: numbers =

[1000000

+ x for x in

range(20

)]start_time = time.time(

) find_sums(numbers)

duration = time.time(

)- start_time

print

(f"duration seconds"

)

GIL 全域性直譯器鎖

1 描述python中gil的概念,以及它對python多執行緒的影響?編寫乙個多執行緒抓取網頁的程式,並闡明多執行緒抓取程式是否可比單執行緒效能有提公升,並解釋原因。答 gil global interpreter lock,即全域性直譯器鎖 1 python語言和gil沒有半毛錢關係。僅僅是由於...

GIL全域性直譯器鎖

gil 啥?他是如何產生的?gil產生的背景 在cpython解釋內部執行多個執行緒的時候,每個執行緒都需要直譯器內部申請相應的全域性資源,由於c語言本身比較底層造成cpython在管理所有全域性資源的時候並不能應對所有執行緒同時的資源請求,因此為了防止資源競爭而發生錯誤,對所有執行緒申請全域性資源...

全域性直譯器鎖GIL

我們使用高併發,一次是建立1萬個執行緒去修改乙個數並列印結果看現象 from threading import thread import osdef func args global n n args print n,os.getpid n 100t list for i in range 100...