python - 文件 I/O 操作会释放 Python 中的 GIL 吗?

标签 python python-3.x multithreading concurrency gil

基于我所阅读的内容 - 例如 here - 我了解 I/O 操作会释放 GIL。因此,如果我必须读取本地文件系统上的大量文件,我的理解是线程执行应该会加快速度。

为了对此进行测试 - 我有一个文件夹 (input),其中包含大约 100k 个文件 - 每个文件只有一行和一个随机整数。我有两个功能 - 一个“顺序”和一个“并发”,只是将所有数字相加

import glob
import concurrent.futures
ALL_FILES = glob.glob('./input/*.txt')
  
def extract_num_from_file(fname):
    #time.sleep(0.1)
    with open(fname, 'r') as f:
        file_contents = int(f.read().strip())
    return file_contents

def seq_sum_map_based():
   return sum(map(extract_num_from_file, ALL_FILES)) 

def conc_sum_map_based():
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        return sum(executor.map(extract_num_from_file, ALL_FILES))

虽然这两个函数给我相同的结果 - “并发”版本慢了大约 3-4 倍。

In [2]: %timeit ss.seq_sum_map_based()                                                                                                     
3.77 s ± 50.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [3]: %timeit ss.conc_sum_map_based()                                                                                                    
12.8 s ± 240 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

我的代码或我的理解有问题吗?

最佳答案

注意:以下内容仅适用于 HDD,HDD 具有可影响读取吞吐量的移动部件,不适用于 SDD。巨大性能差异的性质让我清楚地知道这是一个面向 HDD 的问题,因此此信息是在该假设下运行的。

问题在于,虽然线程可能并行运行,但数据必须从硬盘驱动器顺序读取,因为只有一个读头。然而,更糟糕的是,由于您已经并行化了 I/O 操作,底层操作系统将安排这些 I/O 任务,以便在切换到另一个线程之前仅部分处理这些文件——毕竟,即使您只有一个整数,文件头仍然需要处理——导致读取头比在严格顺序代码中跳得更疯狂。与不需要那么多跳转的简单地按顺序读取每个文件的全部内容相比,所有这些都会导致开销大大增加。

例如,如果您有一个线程从磁盘加载大量数据,而第二个线程对它执行一些时间密集型处理,那么这就不是什么大问题,因为这样可以节省时间- 密集处理继续不受 I/O 操作阻塞。您的特定场景只是一个非常非常糟糕的情况,您放弃了 GIL 瓶颈以换取极其缓慢的 I/O 瓶颈。

简而言之,您已经正确地理解了 I/O 操作释放 GIL,您只是对并行文件读取得出了错误的结论。

关于python - 文件 I/O 操作会释放 Python 中的 GIL 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70509732/

相关文章:

python - Django:并行运行几个任务

python - Python 的 logging.config.dictConfig() 是否应用记录器的配置设置?

java - Java 不一致状态比较

python - 在 httplib.HTTPConnection 上多次发送,在 HTTPResponse 上多次读取?

python - 类型错误 : graph_def must be a GraphDef proto

python - Django-Guardian - 限制组对类的访问

c++ - thread_local "storage class specified"

c++ - 将类对象传递给线程

python - 列表索引超出范围 - Python 索引错误

python - OOP设计中的实例错误: Instance of Card has No points member