Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中多线程的I/O减速_Python_Multithreading_Memory_Io - Fatal编程技术网

python中多线程的I/O减速

python中多线程的I/O减速,python,multithreading,memory,io,Python,Multithreading,Memory,Io,我有一个python脚本,它在以下方案中工作:读取一个大文件(例如电影)-将选定的信息从中合成为一些小的临时文件-在子流程中生成一个C++应用程序来执行文件处理/计算(分别针对每个文件)-读取应用程序输出。为了加速脚本,我使用了多处理。但是,它有一个主要缺点:每个进程都必须在RAM中维护大输入文件的整个副本,因此我只能运行几个进程,因为我的内存不足。因此,由于线程共享地址空间的事实,我决定尝试多线程(或者多处理和多线程的某种组合)。由于python部分大部分时间使用文件I/O或等待C++应用程序

我有一个
python
脚本,它在以下方案中工作:读取一个大文件(例如电影)-将选定的信息从中合成为一些小的临时文件-在子流程中生成一个
C++
应用程序来执行文件处理/计算(分别针对每个文件)-读取应用程序输出。为了加速脚本,我使用了多处理。但是,它有一个主要缺点:每个进程都必须在RAM中维护大输入文件的整个副本,因此我只能运行几个进程,因为我的内存不足。因此,由于线程共享地址空间的事实,我决定尝试多线程(或者多处理和多线程的某种组合)。由于
python
部分大部分时间使用文件
I/O
或等待
C++
应用程序完成,因此我认为
GIL
在这里一定不是问题。然而,我观察到的不是性能上的一些提高,而是急剧下降,主要是由于
I/O部分

我用以下代码说明了问题(另存为
test.py
):

有人能给我解释一下结果,并给出一些建议,如何使用多线程有效地并行化
I/O

编辑:

减速不是由于硬盘性能,因为:

1) 无论如何,这些文件都会被缓存到RAM中


2) 使用多处理(而不是多线程)的相同操作确实正在变得更快(几乎是CPU数量的一个因素)

我认为您的性能指标没有撒谎:您要求您的硬盘同时做许多事情。关闭文件时读取、写入、fsync。。。并同时在多个文件上。它会触发许多硬件物理操作。而且,您同时编写的文件越多,您会遇到越多的争用

所以CPU正在等待磁盘操作完成

此外,可能您没有SSD硬盘,因此同步实际上意味着一些物理移动

编辑:这可能是GIL的问题。在run_io中迭代obj中的elem时,在每次写入之间执行python代码。write可能会释放GIL,这样IO就不会阻塞其他线程,但每次迭代都会释放/获取锁。所以,也许你的写作不是真的“同时”进行的

编辑2:要检验假设,您可以尝试替换:

for elem in obj:
    ofile.write(elem)
与:


当我深入研究这个问题时,我为4种不同的并行化方法做了比较基准,其中3种使用
python
,1种使用
java
(测试的目的不是比较不同语言之间的I/O机制,而是看看多线程是否可以提高I/O操作)。测试在Ubuntu 14.04.3上执行,所有文件都放在RAM磁盘上

尽管数据非常嘈杂,但明显的趋势是显而易见的(见图表;每个条n=5,错误条代表SD):python多线程无法提高I/O性能。最可能的原因是GIL,因此没有办法解决它


Sidenote-我一直喜欢使用
多处理
多处理.dummy
来轻松测试多处理与多线程问题。它提供了一个简单的API,并且可以在进程和线程之间轻松切换。您考虑过使用内存映射吗?它可以将文件映射到内存中,但在进程之间共享操作系统将在必要时执行实际的IO。当不再使用时,它也会释放RAM,即不再交换。即使在GIL的最坏情况下,我也希望运行时与GIL相当,而不是2倍的慢。更换后不会有任何改善
$ python3 test.py 1
Runtime: 2.84 s
$ python3 test.py 1
Runtime: 2.77 s
$ python3 test.py 1
Runtime: 3.34 s
$ python3 test.py 2
Runtime: 6.54 s
$ python3 test.py 2
Runtime: 6.76 s
$ python3 test.py 2
Runtime: 6.33 s
for elem in obj:
    ofile.write(elem)
ofile.write("".join(obj))