<p>问题是我没有正确使用<code>QThread</code>。在</p>
<p>印刷的结果</p>
<pre><code>print("(Current Thread)", QThread.currentThread(),"\n")
print("(Current Thread)", int(QThread.currentThreadId()),"\n")
</code></pre>
<p>注意到我创建的<code>PickleDumpingThread</code>是在主线程中运行的,而不是在某个单独的线程中运行。在</p>
<p>这是因为<code>run()</code>是<code>QThread</code>中唯一在独立线程中运行的函数,所以像<code>QThread</code>中的<code>savePickle</code>这样的方法在主线程中运行。在</p>
<hr/>
<p><strong>第一个解决方案</strong></p>
<p>using signal的正确用法是使用Worker,如下所示。在</p>
^{pr2}$
<p>这个解决方案是可行的(pickle被转储在单独的线程中),但是它的缺点是由于signal emit()函数,数据流仍然延迟大约0.5~1秒。在</p>
<p>我发现对于我的情况,最好的解决方案是@PYPL的代码,但是代码需要一些修改才能工作。在</p>
<hr/>
<p><strong>最终解决方案</strong></p>
<p>最终的解决方案是修改@PYPL的以下代码</p>
^{3}$
<p>到</p>
<pre><code>self.thread = PickleDumpingThread(self.dataDeque)
self.thread.start()
</code></pre>
<p>原始代码有一些运行时错误。线程在转储pickle之前似乎被垃圾回收了,因为<code>onData()</code>函数完成后没有对该线程的引用。在</p>
<p>通过添加<code>self.thread</code>引用线程解决了这个问题。在</p>
<p>而且,旧的<code>PickleDumpingThread</code>似乎是在新的<code>PickleDumpingThread</code>被{<cd8>}引用之后被垃圾回收的(因为旧的<code>PickleDumpingThread</code>丢失了它的引用)。在</p>
<p>但是,这个声明没有被证实(因为我不知道如何查看当前活动线程)。。在</p>
<p>不管怎样,这个解决方案解决了问题。在</p>
<hr/>
<p><strong>编辑</strong></p>
<p>我的最终解决方案也有延迟。打电话要花一些时间线程启动().. 在</p>
<p>我选择的最终解决方案是在线程中运行无限循环,并监视该线程的一些变量,以确定何时保存pickle。仅仅在线程中使用无限循环就需要大量的cpu,所以我添加了时间。睡觉(0.1)以降低cpu使用率。在</p>
<hr/>
<p><strong>最终编辑</strong></p>
<p>好吧,我的“最终解决方案”也有延迟。。
即使我将转储作业移到另一个QThread,主线程仍有pickle转储时间的延迟!太奇怪了。在</p>
<p>但我找到了原因。原因既不是emit()的性能,也不是我所想的。在</p>
<p>令人尴尬的是,原因是<a href="https://stackoverflow.com/questions/18114285/python-what-are-the-differences-between-the-threading-and-multiprocessing-modul/18114882#18114882">python's Global Interpreter Lock prevents two threads in the same process from running Python code at the same time</a>。在</p>
<p>所以在本例中,我可能应该使用<a href="https://docs.python.org/3.4/library/multiprocessing.html" rel="nofollow noreferrer">multiprocessing</a>模块。在</p>
<p>我将在修改代码以使用<a href="https://docs.python.org/3.4/library/multiprocessing.html" rel="nofollow noreferrer">multiprocessing</a>模块后发布结果。在</p>
<p><strong>在使用<code>multiprocessing</code>模块和以后的尝试后进行编辑</strong></p>
<p><strong>使用<code>multiprocessing</code>模块</strong></p>
<p>使用<code>multiprocessing</code>模块解决了并发运行python代码的问题,但是出现了新的本质问题。新的问题是“在进程之间传递共享内存变量需要相当长的时间”(在我的例子中,将<code>deque</code>对象传递到子进程需要1~2秒)。我发现只要我使用<code>multiprocessing</code>模块,这个问题就无法消除。所以我放弃了使用多处理模块</p>
<p><strong>未来可能的尝试</strong></p>
<p><strong>1。{/strong>仅在文件中执行</strong}</p>
<p>pickle转储的本质问题不是写入文件,而是在写入文件之前序列化。Python在写入文件时释放GIL,因此磁盘I/O可以在<code>QThread</code>中并发完成。问题是,在用<code>pickle.dump</code>方法写入文件之前,将<code>deque</code>对象序列化为字符串需要一些时间,而在此期间,由于GIL,主线程将被阻塞。在</p>
<p>因此,下面的方法将有效地减少延迟的长度。在</p>
<ol>
<li><p>每次调用<code>onData()</code>时,我们都会以某种方式对数据对象进行字符串化,并将其推送到deque object</p></li>
<li><p>在<code>PickleDumpingThread</code>中,只要<code>join</code>对象<code>list(deque)</code>来字符串化<code>deque</code>对象。</p></li>
<li><p><code>file.write(stringified_deque_object)</code>。这可以同时进行。</p></li>
</ol>
<p>第一步只需要很短的时间,所以几乎不需要块k主螺纹。
步骤2可能需要一些时间,但显然比在<code>pickle.dump</code>方法中序列化python对象花费的时间要短。
步骤3不阻塞主线程。在</p>
<p><strong>2。使用C扩展名</strong></p>
<p>我们可以手动释放GIL并在我们定制的C扩展模块中重新获取GIL。但这可能是肮脏的。在</p>
<p><strong>3。将CPython移植到Jython或IronPython</strong></p>
<p>Jython和IronPython是其他分别使用Java和C的python实现。因此,它们在实现中不使用GIL,这意味着<code>thread</code>的工作方式与线程类似。
一个问题是这些实现中不支持<code>PyQt</code>。。在</p>
<p><strong>4。移植到另一种语言</strong></p>
<p>。。在</p>
<p>注:</p>
<ol>
<li><p><code>json.dump</code>我的数据也花了1~2秒。</p></li>
<li><p>Cython不是这个案子的选择。尽管Cython有<code>with nogil:</code>,但在该块中只能访问非python对象(<code>deque</code>对象不能在该块中访问),并且我们不能在该块中使用<code>pickle.dump</code>方法。</p></li>
</ol>