涉及pyqt时文件复制太慢
File copy too slow when pyqt is involved
我正在使用此代码(非常简化的原始版本,但问题仍然存在)来复制文件:
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 中调用它时 window,复制速度要慢三倍。
快速复制大量文件是应用程序的重点,我认为包括 gui 会稍微慢一点,但不会慢三倍!!并且 运行 使用线程或多进程的复制功能不会带来令人满意的改进。
这是原样吗?你能推荐我一些东西来解决这个性能问题吗?
编辑:There 是我实际复制代码的要点,运行 并且没有 PyQT
这可能是 GIL 的影响。在 UI 线程中使用 PyQt 运行,它 "steals" GIL 每次必须处理事件时。这意味着您上面的循环每次都会停止。当您 运行 在另一个线程中时,也会发生这种情况;锁是 global.
解决方法:
- 使用更大的缓冲区。 Python的C层不受GIL的影响,所以如果你复制的数据量较大,循环中的命令执行的频率就会降低。
- 执行外部命令进行复制(可能是另一个 Python 进程)。
- 使用 Qt 的 IO 类 复制文件,因为它们也不受 GIL 的影响(感谢 ekhumoro 的想法)。
- 用 C 编写一段代码来传输数据。
- 使用没有像 IronPython 或 Jython 这样的 GIL 的 Python 版本。
由于我无法使问题中的链接代码正常工作(它只是挂起并使用 100% CPU),我将 post 一个更合理的示例用于测试目的。
使用下面的测试用例,我在复制一个 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_())
我正在使用此代码(非常简化的原始版本,但问题仍然存在)来复制文件:
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 中调用它时 window,复制速度要慢三倍。
快速复制大量文件是应用程序的重点,我认为包括 gui 会稍微慢一点,但不会慢三倍!!并且 运行 使用线程或多进程的复制功能不会带来令人满意的改进。
这是原样吗?你能推荐我一些东西来解决这个性能问题吗?
编辑:There 是我实际复制代码的要点,运行 并且没有 PyQT
这可能是 GIL 的影响。在 UI 线程中使用 PyQt 运行,它 "steals" GIL 每次必须处理事件时。这意味着您上面的循环每次都会停止。当您 运行 在另一个线程中时,也会发生这种情况;锁是 global.
解决方法:
- 使用更大的缓冲区。 Python的C层不受GIL的影响,所以如果你复制的数据量较大,循环中的命令执行的频率就会降低。
- 执行外部命令进行复制(可能是另一个 Python 进程)。
- 使用 Qt 的 IO 类 复制文件,因为它们也不受 GIL 的影响(感谢 ekhumoro 的想法)。
- 用 C 编写一段代码来传输数据。
- 使用没有像 IronPython 或 Jython 这样的 GIL 的 Python 版本。
由于我无法使问题中的链接代码正常工作(它只是挂起并使用 100% CPU),我将 post 一个更合理的示例用于测试目的。
使用下面的测试用例,我在复制一个 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_())