手动设置互斥锁会提高性能吗?

我的python程序绝对是cpu绑定的,但是所花费时间的40%至55%是在z3求解器中的C代码中执行的(对于gil则一无所知),其中每个对C函数( {1}}花费了将近一分钟的时间(到目前为止,z3_optimize_check参数仍使该函数在单线程模式下工作并阻塞了主线程)。

我不能使用多重处理,因为z3_objects不易于序列化(除非这里有人可以证明)。由于它们是多个任务(每个任务在其他任务的字典中添加了更多z3工作),因此我最初直接设置了多线程。但是尽管在求解器上花费了大量时间,但Gil绝对会损害性能,而不是带来好处(尤其是超线程)。

但是,如果我在从C代码切换后立即在z3py模块中手动设置了阻塞互斥(通过parallel_enable),这将允许仅在所有其他线程都在执行求解器工作的情况下运行另一个线程,这会不会删除gil性能损失(因为执行python代码时它们只有1个线程,并且在threading.Lock.aquire()之前释放锁之前,它将始终是一个线程)?
我是说使用z3_optimize_check会触发对threading.Lock.aquire()的调用,就像z3直接在执行此操作一样?

qq376055355 回答:手动设置互斥锁会提高性能吗?

  

到目前为止,parallel_enable参数仍然导致此函数在单线程模式下工作并阻塞主线程

我认为您对此误解。 z3在并行模式下运行意味着您可以从单个Python线程调用它,然后它为自己生成多个OS级线程,从而完成工作,清理线程并为您返回结果。它不能奇迹般地使没有GIL的Python运行。
从Python的角度来看,它一次仍然执行一件事,而另一件事是调用z3。它一直保持着GIL。因此,如果在运行计算时看到一个以上的CPU内核/线程被使用,那是z3并行模式的影响,内部分支到多个线程。

还有另一件事,就是释放GIL,就像阻止I / O操作一样。魔术不会发生这种情况,为此有一个呼叫对:

  

PyThreadState * PyEval_SaveThread()
  释放全局解释器锁(如果已创建),并将线程状态重置为NULL,返回先前的线程状态(非NULL)。如果已创建锁,则当前线程必须已获取它。

     

无效 PyEval_RestoreThread(PyThreadState * tstate)
  获取全局解释器锁(如果已创建),并将线程状态设置为 tstate ,该状态不能为NULL。如果已创建锁,则当前线程一定不能获取它,否则会发生死锁。

这些是C调用,因此扩展开发人员可以访问它们。当开发人员知道代码可以运行很长时间而无需访问Python内部时,可以使用PyEval_SaveThread(),然后Python可以继续使用其他Python线程。而且,无论什么时候做完,线程都可以重新引入自身,并使用PyEval_RestoreThread()申请GIL。
但是,只有当开发人员使它们发生时,这些事情才会发生。使用z3可能并非如此。

要直接回答您的问题:不,Python代码不能释放GIL并保持其释放状态,因为GIL是Python线程在处理过程中必须持有的锁。因此,每当返回Python“指令”时,GIL就会再次保留。


显然,我设法以某种方式不包含我想要的链接,所以它们位于页面https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock上(链接的段落讨论了我不久总结的内容)。

Z3是开放源代码(https://github.com/Z3Prover/z3),并且源代码既不包含PyEval_SaveThread,也不包含包装快捷键Py_BEGIN_ALLOW_THREADS的字符序列。


但是,它有一个并行的Python示例btw。 https://github.com/Z3Prover/z3/blob/master/examples/python/parallel.py,并

from multiprocessing.pool import ThreadPool

所以我认为它可能已经过测试并且可以与multiprocessing一起使用。

本文链接:https://www.f2er.com/3165815.html

大家都在问