我正在编写科学计算领域的Python应用程序。目前,当用户使用GUI并开始新的物理模拟时,解释器会立即为此模拟导入几个必要的模块,例如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.
你知道这样的事吗?如果没有,您对设计有什么建议吗?
答案 0 :(得分:2)
问题在于导入必须在可用之前完成。根据它们何时首次使用,应用程序可能仍然需要阻止10秒才能启动它。更有成效的是对模块进行分析并找出为什么它们需要很长时间才能导入。
答案 1 :(得分:2)
为什么不在应用程序启动时执行此操作?
def background_imports():
import Traits
import Mayavi
thread = threading.Thread(target=background_imports)
thread.setDaemon(True)
thread.start()
答案 2 :(得分:1)
一般的想法很好,但是当后台线程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
)在zipfile中并从那里导入(但这仅对I / O开销有所帮助,具体取决于您的操作系统,文件系统和驱动器:由于加载而导致的延迟无效加载时包中的巨大DLL或执行初始化代码,我怀疑这是缓慢的罪魁祸首。
您还可以考虑将应用程序与multiprocessing
分开 - 再次使用队列(但是多处理类型)进行通信 - 以便将导入和一些繁重的计算委托给一些辅助进程,从而异步(这也可能有助于一次完全利用多个核心)。我怀疑遗憾的是,对于可视化任务(例如你可能使用mayavi做的那些)来说,这可能很难妥善安排,但如果你还有一些“纯粹的重计算”包和任务,它可能会有所帮助。
答案 3 :(得分:-1)
“用户使用GUI并启动新的物理模拟”
不太清楚。 “与GUI一起使用”是否意味着双击?双击什么?一些wxWidgets GUI应用程序?还是空闲?
如果是这样,“开始一个新的物理模拟”是什么意思?点击其他地方的按钮?一个GUI按钮,用于显示他们编写代码的面板?或者他们导入他们离线写的脚本?
为什么在模拟开始之前进行导入?模拟需要多长时间? GUI显示什么?
我怀疑在做大进口方面有一种方法可以变得更加懒散。但是从描述来看,很难确定导入对用户来说无关紧要的时间点。
线程没有多大帮助。有助于重新思考UI体验。