GIL如何处理块I/O读/写?

2024-06-01 01:22:53 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个io.BytesIO()我想写一个关于坐在线程上的响应:

f = io.ByteIO()
with requests.Session() as s:
    r = s.get(url, stream = True)
    for chunk in r.iter_content(chunk_size = 1024):
        f.write(chunk)

现在这不是硬盘,而是内存(我有足够的目的),所以我不必担心针是一个瓶颈。我知道对于阻塞I/O(文件读/写),GIL是由Alex Martelli从docspost释放的,但是我想知道,GIL是在f.write()上释放,然后在__next__()循环调用上重新获取的吗?你知道吗

所以我最终得到的是一堆快速的GIL收购和发行。很明显,我必须计时以确定任何值得注意的事情,但是在多线程web scraper上写入内存中的文件对象通常支持GIL绕过?你知道吗

如果没有,我将只处理大型响应并将它们转储到队列中,然后在__main__上进行处理。你知道吗


Tags: 文件内存iourlgetsessionaswith
1条回答
网友
1楼 · 发布于 2024-06-01 01:22:53

^{} type's source code中可以看到,GIL在调用BytesIO.write期间没有被释放,因为它只是做一个快速内存拷贝。只有系统调用可能会阻止GIL的释放才有意义。你知道吗

r.iter_content生成器的__next__方法中可能有这样一个系统调用(当从套接字读取数据时),但在写端没有。你知道吗

但我认为你的问题反映了一种错误的理解,即在执行阻塞操作时,对于一个内置函数释放GIL意味着什么。它将在执行可能阻塞的系统调用之前释放GIL。但它将在返回Python代码之前重新获取GIL。因此,不管在一个循环中有多少这样的GIL释放操作,所有涉及的Python代码都将在GIL保持的情况下运行。GIL从不通过一次操作释放,而是通过不同的操作回收。作为一个独立的步骤,每个操作都会释放和回收它。你知道吗

例如,您可以查看the C code that implements writing to a file descriptor。宏Py_BEGIN_ALLOW_THREADS释放GIL。几行之后,Py_END_ALLOW_THREADS重新获得了GIL。在这些步骤之间没有Python级别的运行,只有一些关于errno的低级C赋值,以及可能阻塞的write系统调用在磁盘上等待。你知道吗

相关问题 更多 >