AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

通過研究案例,徹底掌握Python GIL

來源: 責編: 時間:2023-11-04 23:04:50 326觀看
導(dǎo)讀Python因其全局解釋器鎖(GIL)而聲名狼藉。GIL限制了Python解釋器一次只能執(zhí)行一個線程。在現(xiàn)代多核CPU上,這是一個問題,因為程序無法利用多個核心。不過,盡管存在這種限制,Python仍已成為從后端Web應(yīng)用到AI/ML和科學計算等

Python因其全局解釋器鎖(GIL)而聲名狼藉。GIL限制了Python解釋器一次只能執(zhí)行一個線程。在現(xiàn)代多核CPU上,這是一個問題,因為程序無法利用多個核心。不過,盡管存在這種限制,Python仍已成為從后端Web應(yīng)用到AI/ML和科學計算等領(lǐng)域的頂級語言。hk128資訊網(wǎng)——每日最新資訊28at.com

1、訓練數(shù)據(jù)管道的結(jié)構(gòu)

對于大多數(shù)后端Web應(yīng)用來說,GIL的限制并不是一個約束,因為它們通常受到I/O的限制。在這些應(yīng)用中,大部分時間只是等待來自用戶、數(shù)據(jù)庫或下游服務(wù)的輸入。系統(tǒng)只需具備并發(fā)性,而不一定需要并行性。Python解釋器在執(zhí)行I/O操作時會釋放GIL,因此當線程等待I/O完成時,就會給另一個線程獲得GIL并執(zhí)行的機會。hk128資訊網(wǎng)——每日最新資訊28at.com

GIL的限制不會影響大多數(shù)計算密集型的AI/ML和科學計算工作負載,因為像NumPy、TensorFlow和PyTorch等流行框架的核心實際上是用C++實現(xiàn)的,并且只有Python的API接口。大部分計算可以在不獲取GIL的情況下進行。這些框架使用的底層C/C++內(nèi)核庫(如OpenBLAS或Intel MKL)可以利用多個核心而不受GIL的限制。hk128資訊網(wǎng)——每日最新資訊28at.com

當同時有I/O和計算任務(wù)時會發(fā)生什么?hk128資訊網(wǎng)——每日最新資訊28at.com

2、使用純Python的計算任務(wù)

具體來說,可以考慮以下兩個簡單的任務(wù)。hk128資訊網(wǎng)——每日最新資訊28at.com

import timedef io_task():    start = time.time()    while True:        time.sleep(1)        wake = time.time()        print(f"woke after: {wake - start}")        start = wake        def count_py(n):  compute_start = time.time()  s = 0  for i in range(n):      s += 1  compute_end = time.time()  print(f"compute time: {compute_end - compute_start}")  return s

在這里,通過休眠一秒鐘來模擬一個I/O限制的任務(wù),然后喚醒并打印它休眠了多長時間,然后再次休眠。count_py是一個計算密集型的任務(wù),它簡單地對數(shù)字n進行計數(shù)。如果同時運行這兩個任務(wù)會發(fā)生什么?hk128資訊網(wǎng)——每日最新資訊28at.com

import threadingio_thread = threading.Thread(target=io_task, daemnotallow=True)io_thread.start()count_py(100000000)

輸出結(jié)果如下:hk128資訊網(wǎng)——每日最新資訊28at.com

woke after: 1.0063529014587402woke after: 1.009704828262329woke after: 1.0069530010223389woke after: 1.0066332817077637compute time: 4.311860084533691

count_py需要大約4.3秒才能計數(shù)到一百萬。但是io_task在同一時間內(nèi)運行而不受影響,大約在1秒后醒來,與預(yù)期相符。盡管計算任務(wù)需要4.3秒,但Python解釋器可以預(yù)先從運行計算任務(wù)的主線程中釋放GIL,并給予io_thread獲得GIL并運行的機會。hk128資訊網(wǎng)——每日最新資訊28at.com

3、使用numpy的計算任務(wù)

現(xiàn)在,本文將在numpy中實現(xiàn)計數(shù)函數(shù),并進行與之前相同的實驗,但這次要計數(shù)到一千萬,因為numpy的實現(xiàn)效率更高。hk128資訊網(wǎng)——每日最新資訊28at.com

import numpy as npdef count_np(n):    compute_start = time.time()    s = np.ones(n).sum()    compute_end = time.time()    print(f"compute time: {compute_end - compute_start}")    return s  io_thread = threading.Thread(target=io_task, daemnotallow=True)io_thread.start()count_np(1000000000)

輸出結(jié)果如下:hk128資訊網(wǎng)——每日最新資訊28at.com

woke after: 1.0001161098480225woke after: 1.0008511543273926woke after: 1.0004539489746094woke after: 1.1320469379425049compute time: 4.1334803104400635

這顯示的結(jié)果與上一次實驗類似。在這種情況下,不是Python解釋器預(yù)先釋放了GIL,而是numpy自己主動釋放了GIL。hk128資訊網(wǎng)——每日最新資訊28at.com

這是否意味著在獨立的線程中同時運行I/O任務(wù)和計算任務(wù)總是安全的?hk128資訊網(wǎng)——每日最新資訊28at.com

4、使用自定義C++擴展的計算任務(wù)

現(xiàn)在,本文將用Python的C++擴展實現(xiàn)計數(shù)函數(shù)。hk128資訊網(wǎng)——每日最新資訊28at.com

// importing Python C API Header#include <Python.h>#include <vector>static PyObject *count(PyObject *self, PyObject *args){  long num;  if (!PyArg_ParseTuple(args, "l", &num))         return NULL;  long result = 0L;  std::vector<long> v(num, 1L);  for (long i=0L; i<num; i++) {    result += v[i];   }  return Py_BuildValue("l", result);}// defining our functions like below:// function_name, function, METH_VARARGS flag, function documentsstatic PyMethodDef functions[] = {  {"count", count, METH_VARARGS, "Count."},  {NULL, NULL, 0, NULL}};// initializing our module informations and settings in this structure// for more informations, check head part of this file. there are some important links out there.static struct PyModuleDef countModule = {  PyModuleDef_HEAD_INIT, // head informations for Python C API. It is needed to be first member in this struct !!  "count",  // module name  NULL,  -1,  functions  // our functions list};// runs while initializing and calls module creation function.PyMODINIT_FUNC PyInit_count(void){  return PyModule_Create(&countModule);}

可以通過運行python setup.py build來構(gòu)建擴展,使用以下setup.pyhk128資訊網(wǎng)——每日最新資訊28at.com

from distutils.core import setup, Extensioncount_module = Extension('count', sources=['count.cpp'])setup(name='python_count_extension',      versinotallow='0.1',      descriptinotallow='An Example For Python C Extensions',      ext_modules=[count_module],      )

然后,使用作為自定義擴展實現(xiàn)的計數(shù)函數(shù)運行實驗:hk128資訊網(wǎng)——每日最新資訊28at.com

import count def count_custom(n):    compute_start = time.time()    s = count.count(n)    compute_end = time.time()    print(f"compute time: {compute_end - compute_start}")    return sio_thread = threading.Thread(target=io_task, daemnotallow=True)io_thread.start()count_custom(1000000000)

得到如下結(jié)果:hk128資訊網(wǎng)——每日最新資訊28at.com

woke after: 4.414866924285889compute time: 4.414893865585327

在這種情況下,計算任務(wù)持有GIL,并阻止I/O線程運行。hk128資訊網(wǎng)——每日最新資訊28at.com

Python解釋器只能在兩個Python字節(jié)碼指令之間預(yù)先釋放GIL,在擴展中,是否自愿釋放GIL取決于擴展的實現(xiàn)。hk128資訊網(wǎng)——每日最新資訊28at.com

在這種情況下,本例進行了一個不會影響任何Python對象的瑣碎計算,因此可以在C++的計數(shù)函數(shù)中使用宏Py_BEGIN_ALLOW_THREADSPy_END_ALLOW_THREADS來釋放GIL:hk128資訊網(wǎng)——每日最新資訊28at.com

static PyObject *count(PyObject *self, PyObject *args){  long num;  if (!PyArg_ParseTuple(args, "l", &num))         return NULL;  long result = 0L;  Py_BEGIN_ALLOW_THREADS  std::vector<long> v(num, 1L);  for (long i=0L; i<num; i++) {    result += v[i];   }   Py_END_ALLOW_THREADS  return Py_BuildValue("l", result);}

使用這種實現(xiàn)方式,當重新運行實驗時,會得到如下結(jié)果:hk128資訊網(wǎng)——每日最新資訊28at.com

woke after: 1.0026037693023682woke after: 1.003467082977295woke after: 1.0028629302978516woke after: 1.1772480010986328compute time: 4.186192035675049

5、結(jié)論

在使用Python時,了解GIL是很重要的。在大多數(shù)常見情況下,可能不會遇到它的限制。但是,如果使用包裝C/C++庫的第三方Python包(除了標準的NumPy、SciPy、TensorFlow或PyTorch),在涉及到任何重型計算時可能會遇到一些問題。在開發(fā)自定義擴展時,最好在進行重型計算之前釋放GIL,以便其他Python線程有機會運行。hk128資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-16939-0.html通過研究案例,徹底掌握Python GIL

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Sed 原地替換文件時遇到的趣事

下一篇: 五個使用IntelliJ IDEA優(yōu)化Java代碼的小技巧

標簽:
  • 熱門焦點
Top