我正在尝试模拟使用 twisted 运行的应用程序网络。作为我模拟的一部分,我想同步某些事件并能够为每个进程提供大量数据。我决定使用多处理事件和队列。但是,我的进程挂起。
我写了下面的示例代码来说明问题。具体而言,(在我的 sandy bridge 机器上,大约 95% 的时间)“run_in_thread”函数完成,但是直到我按下 Ctrl-C 后才会调用“print_done”回调。
此外,我可以更改示例代码中的几项内容以使其更可靠地工作,例如:减少派生进程的数量、从 reactor_ready 调用 self.ready.set 或更改 deferLater 的延迟。
我猜测在扭曲的 react 器和阻塞的多处理调用(例如 Queue.get() 或 Event.wait())之间存在竞争条件?
我遇到的问题到底是什么?我的代码中是否存在我遗漏的错误?我可以解决这个问题还是与多处理事件/队列不兼容?
其次,像 spawnProcess 或 Ampoule 这样的东西是推荐的替代品吗? (如 Mix Python Twisted with multiprocessing? 中所建议)
编辑(按要求):
我在尝试 glib2reactor selectreactor、pollreactor 和 epollreactor 时遇到了所有反应器的问题。 epollreactor 似乎给出了最好的结果,并且对于下面给出的示例似乎工作正常,但在我的应用程序中仍然给我相同(或类似)的问题。我会继续调查。
我正在运行 Gentoo Linux 内核 3.3 和 3.4、python 2.7,并且我已经尝试过 Twisted 10.2.0、11.0.0、11.1.0、12.0.0 和 12.1.0。
除了我的 sandy bridge 机器,我在我的双核 amd 机器上也看到了同样的问题。
#!/usr/bin/python
# -*- coding: utf-8 *-*
from twisted.internet import reactor
from twisted.internet import threads
from twisted.internet import task
from multiprocessing import Process
from multiprocessing import Event
class TestA(Process):
def __init__(self):
super(TestA, self).__init__()
self.ready = Event()
self.ready.clear()
self.start()
def run(self):
reactor.callWhenRunning(self.reactor_ready)
reactor.run()
def reactor_ready(self, *args):
task.deferLater(reactor, 1, self.node_ready)
return args
def node_ready(self, *args):
print 'node_ready'
self.ready.set()
return args
def reactor_running():
print 'reactor_running'
df = threads.deferToThread(run_in_thread)
df.addCallback(print_done)
def run_in_thread():
print 'run_in_thread'
for n in processes:
n.ready.wait()
def print_done(dfResult=None):
print 'print_done'
reactor.stop()
if __name__ == '__main__':
processes = [TestA() for i in range(8)]
reactor.callWhenRunning(reactor_running)
reactor.run()
最佳答案
简短的回答是肯定的,Twisted 和多处理彼此不兼容,您不能像您尝试的那样可靠地使用它们。
在所有 POSIX 平台上,子进程管理与 SIGCHLD 处理密切相关。 POSIX 信号处理程序是进程全局的,每个信号类型只能有一个。
Twisted 和 stdlib multiprocessing 不能同时安装 SIGCHLD 处理程序。只有他们中的一个可以。这意味着只有其中一个可以可靠地管理子进程。您的示例应用程序无法控制它们中的哪一个将赢得该能力,因此我预计它的行为会因该事实而产生一些不确定性。
但是,您的示例更直接的问题是您在父进程中加载 Twisted,然后使用 multiprocessing 派生 而不是执行 所有子进程。 Twisted 不支持这样使用。如果你 fork 然后 exec,就没有问题。但是,缺少新进程的执行程序(可能是使用 Twisted 的 Python 进程)会导致 Twisted 无法解决的各种额外共享状态。在您的特定情况下,导致此问题的共享状态是用于实现 deferToThread 的内部“waker fd”。由于父进程和所有子进程共享 fd,当父进程试图唤醒主线程以传递 deferToThread 调用的结果时,它很可能唤醒其中一个子进程进程代替。子进程没有任何用处,所以那只是浪费时间。同时,父线程中的主线程永远不会醒来,也永远不会注意到您的线程任务已完成。
您可以通过在创建子进程之前不加载任何 Twisted 来避免此问题。就 Twisted 而言,这会将您的使用变成一个单进程用例(在每个进程中,它最初都会被加载,然后该进程将不会继续 fork,所以毫无疑问 fork 和 Twisted 是如何交互的)。这意味着在您创建子进程之前甚至不会导入 Twisted。
当然,这只会帮助您达到 Twisted 的水平。您使用的任何其他库都可能遇到类似的问题(您提到了 glib2,这是另一个库的一个很好的例子,如果您尝试这样使用它,它将完全窒息)。
我强烈建议不要使用 multiprocessing 模块。相反,使用任何涉及 fork 和 exec 的多进程方法,而不是单独使用 fork。安瓶属于这一类。
关于python - 扭曲与多处理事件和队列不兼容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11272874/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的
本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决