我正在编写一个科学计算领域的Python应用程序。目前,当用户使用图形用户界面并启动新的物理模拟时,解释器会立即导入此模拟所需的几个模块,如Traits和Mayavi。这些模块很重,而且导入时间太长,用户必须等待大约10秒才能继续,这是很糟糕的。
我想到了一些可以弥补这个问题的方法。我将描述它,也许其他人已经实现了它,如果是这样,请给我一个链接。如果不是,我可能会自己去做。
我想要的是一个单独的线程,它将异步导入模块。它可能是threading.Thread的一个子类。
下面是一个使用示例:
importer_thread = ImporterThread()
importer_thread.start()
# ...
importer_thread.import('Mayavi')
importer_thread.import('Traits')
# A thread-safe method that will put the module name
# into a queue which the thread in an inifine loop
# ...
# When the user actually needs the modules:
import Mayavi, Traits
# If they were already loaded by importer_thread, we're good.
# If not, we'll just have to wait as usual.你知道有这样的事情吗?如果没有,你对设计有什么建议吗?
发布于 2010-01-15 21:31:46
这样做的问题是,导入仍然必须完成,然后才能使用。根据第一次使用它们的时间,应用程序可能仍然必须阻塞10秒,然后才能启动。更有效的方法是对模块进行概要分析,并找出它们为什么需要这么长时间才能导入。
发布于 2010-01-15 22:47:50
为什么不在应用程序启动时执行此操作?
def background_imports():
import Traits
import Mayavi
thread = threading.Thread(target=background_imports)
thread.setDaemon(True)
thread.start()发布于 2010-01-16 00:01:11
一般的想法是好的,但是当后台线程被锁定(import)时,Python/GUI会话可能不会有那么好的响应;不幸的是,import本质上不可避免地“锁定”了Python (不仅仅是GIL,还有特定的额外的导入锁定)。
尽管如此,仍然值得一试,因为这可能会让事情变得更好--这也非常简单,因为Queue本质上是线程安全的,而且除了Queue的put和get之外,您所需要的基本上只是一个__import__。
如果您有一些本质上非常快的驱动器,但是空间有限,比如"RAM驱动器“或特别快的固态驱动器,那么可能值得将所需的包保存在.tar.bz2 (或其他形式的归档)中,并在程序启动时将其解压缩到快速驱动器(这本质上就是I/O,因此它不会严重锁定-- I/O操作会迅速释放GIL --而且特别容易委托给运行tar xjf或类似文件的子进程)。
如果导入速度慢是由于大量的.py/.pyc/.pyo文件造成的,那么值得一试将这些文件(仅限于.pyc格式,而不是作为.py)保存在for文件中并从那里导入(但这只有助于I/O开销,这取决于您的操作系统、文件系统和驱动器:对于由于加载大量DLL或在加载时执行包中的初始化代码而导致的延迟,我怀疑这更可能是导致速度变慢的罪魁祸首)。
您还可以考虑使用multiprocessing拆分应用程序--同样使用队列(但属于多处理类型)进行通信--以便将导入和一些繁重的计算委托给几个辅助进程,从而使其成为异步的(这也有助于同时充分利用多个内核)。不幸的是,我怀疑这可能很难正确安排可视化任务(比如你可能正在用mayavi做的那些任务),但如果你还有一些“纯粹的繁重计算”包和任务,它可能会有所帮助。
https://stackoverflow.com/questions/2071786
复制相似问题