涉及pyqt时文件复制太慢

时间:2015-10-05 15:11:22

标签: python performance pyqt

我正在使用此代码(非常简化的原始版本,但问题仍然存在)来复制文件:

def copyfileobj_example(source, dest, buffer_size=1024*1024):
    while 1:
        copy_buffer = source.read(buffer_size)
        if not copy_buffer:
            break
        dest.write(copy_buffer)

如果我在没有pyqt的情况下调用该函数,文件将被快速复制,但是当我在一个简单的pyqt窗口中调用它时,副本的速度会慢三倍。

快速复制大量文件是应用程序的主要观点,我认为包括gui会慢一点,但没有让它慢三倍!并使用线程或多进程运行复制功能不会带来令人满意的改进。

这就是这样吗?你能推荐一些解决这个性能问题的东西吗?

编辑:There是我的实际复制代码的要点,使用和不使用PyQT运行

2 个答案:

答案 0 :(得分:5)

这可能是GIL的影响。随着PyQt在UI线程中运行,它每次必须处理事件时“窃取”GIL。这意味着您的循环每次都会停止。当你在另一个线程中运行时也会发生这种情况;锁是全球

解决方法:

  1. 使用更大的缓冲区。 Python的C层不受GIL的影响,因此如果复制大量数据,循环中的命令执行频率会降低。
  2. 执行外部命令进行复制(可能是另一个Python进程)。
  3. 使用Qt的IO类复制文件,因为它不受GIL的影响(对于这个想法感到荣誉为ekhumoro)。
  4. 在C中写一段代码来传输数据。
  5. 使用没有像IronPython或Jython这样的GIL的Python版本。

答案 1 :(得分:2)

由于我无法使问题中的链接代码生效(它只是挂起并使用100%CPU),我将发布一个更健全的示例用于测试。

使用下面的测试用例,我在复制400MB文件(三次运行)时得到以下输出:

$ python copy_test.py
2.9546546936035156
2.9658050537109375
$ python copy_test.py
3.226983070373535
3.192814826965332
$ python copy_test.py
2.935734748840332
2.8552770614624023

如您所见,没有显着差异。为清楚起见,这是在Linux上使用以下设置:

Python 3.5.0, Qt 5.5.0, PyQt 5.5

我得到了与Python 2.7 / 3.5,PyQt 4/5的所有组合类似的结果。

以下是测试用例:

import sys
import time
import os

SRC_FILE = '/home/tmp/source/test/test.zip'
DEST_FILE = '/home/tmp/source/test/test-copy.zip'

def copy_file(src, dst=[], progress=None, only_new_file=True):
    size = 1024 * 1024
    with open(src, 'rb') as s, open(dst[0], 'wb') as d:
        while 1:
            copy_buffer = s.read(size)
            if not copy_buffer:
                break
            d.write(copy_buffer)

if __name__ == '__main__':

    initTime = time.time()
    copy_file(SRC_FILE, [DST_FILE], only_new_file=False)
    print (time.time() - initTime)

    time.sleep(5)

    from PyQt5.QtWidgets import QApplication, QWidget
#     from PyQt4.QtGui import QApplication, QWidget

    app = QApplication(sys.argv)

    w = QWidget()
    w.resize(250, 150)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()

    initTime = time.time()
    copy_file(SRC_FILE, [DST_FILE], only_new_file=False)
    print (time.time() - initTime)

    sys.exit(app.exec_())