如何 运行 一个 zmq 和另一个 while True: 同时独立?
How to run a zmq and other while True: at the same time independently?
我的服务器有这个代码:
import time
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5000")
while True:
message = socket.recv()
socket.send(b"World")
print "sent"
while True:
print "done."
我有一个单独的客户端脚本,每当我发送一条消息时,它都会通过 zmq 向这个脚本发送一条消息。在服务器上(这段代码),如果我只有第一个 while True:,它会在我每次发送消息时打印 "sent",如果我只有第二个 while True:,它会打印 "done."不断地。但是,如果我同时放置两者,它永远不会打印完成(或者如果我切换他们的顺序并同时放置它们,当我发送消息时它永远不会打印 "sent"”)。
作为输出,我希望它连续打印 "done.",并在收到消息时打印 "sent"。所以像这样:
done.
done.
done.
done.
done.
sent
done.
lots more done....
基本上我希望两个循环 运行 连续且完全独立于彼此。
N.B。我曾尝试使用多处理(例如此处的第 3 个答案 How do I run two python loops concurrently?),但也无法使其正常工作。我试过如下:
import time
import zmq
from multiprocessing import Process
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5000")
i = time.time()
def zmq_loop():
while True:
message = socket.recv()
socket.send(b"World")
print "sent"
def done_loop():
global i
while True:
i2 = time.time()-i
if i2%2 == 0:
print "done."
if __name__ == "__main__":
Process(target=zmq_loop).start()
Process(target=done_loop).start()
正如昨天在 中解释的那样,[CONCURRENT]
-处理在 python 中可以通过多种不同的方式在技术上实现,每种方式的成本都不同。
今天,让我们来看看另一种方法 - 使用一个框架,它的开发动机完全相同 - 具有自然的 [CONCURRENT]
-已经在 DNA 中的调度 - 最初旨在轻松编写和流畅操作复杂的 GUI 人机交互 (MMI)。
这个框架可能而且将会帮助你实现很多,因为事实上,它已经在完全相同的场景中得到了很多关注,在这些场景中,必须同时监控不止一件事:
欢迎使用 Tkinter
GUI 框架,我们仅将其用于智能并发操作的事件处理程序。
我多次感到非常惊讶,构建一个相当复杂的有限状态自动机 (FSA) 组合是多么容易,它可以顺利合作(FSA-s 的联盟),使用独立的工具,隔离操作(每个 FSA 的内部逻辑),但能够轻松地将信号/消息从一个 FSA 传播到另一个 FSA。是的,他们实际上可以在 1-event-source-FSA : N-consumer(s)-FSA(s)
在那里你可以创建(使用 ZeroMQ 始终以非阻塞方式)处理程序——一个 "sniffer"定期检查(最好通过超时控制的 .poll()
方法来 { NACK | POSACK }
任何要读取的内容)——另一个 "reader" 用于从 ZeroMQ Socket()
实例实际读取(由来自 "sniffer" 的 POSACK
信号触发,如前所述 - 另一个 "do-a-work-er" 对于任何其他可能希望操作的任务
Tkinter .mainloop()
方法是全局控制器,它为您编排肮脏的工作。
Tkinter 介导的代理协同处理的高级概念从 main()
开始,非常简单:
def main():
root = Tk() # INIT a Tk() instance
root.lift() # + make it visible
app = myApplication( root ) # SET ( [HERE] are all your app gems )
root.mainloop() # START the core event-handling orchestrator
Tkinter 可能看起来像一个充满各种 GUI 小工具的车库,与您的问题无关,但不要惊慌。
Tkinter 拥有非常适合您需求的出色工具。
using control variables 将用作在其他独立且明确未协调的参与者之间存储、发信号和传播值变化的手段(参考文献 "sniffer","reader"、"worker" 和任何其他...)
用于处理定时操作的工具 - 几乎是轻量级实时系统的形式,使用设置了接下来会发生什么的首选时间, .mainloop()
-尚需牢记
明确指定的时间 .after( thisAmountOfMILLISECONDS, callThisFUNCTION )
或自由 .after_idle( callAlwaysThatFUNCTION )
.
使用这些已经很完美的工具,您确实不需要任何其他东西来解决您的任务。
所以剩下的只是原则上在你的创造力下如何重新使用这些智能工具。
一个小演示,
如何使两(3!)件事发生"at the same time independently"
让我们设置案例,当一个人想要同时处理(这里通过打印演示)几个独立的进程时。
>>> #-----------------------------------------------FAST MOCK-UP EXAMPLE
>>> import Tkinter as tk # python27
>>> root = tk.Tk()
>>> root.protocol( "WM_DELETE_WINDOW", root.quit() )
'3071841620Ldestroy'
>>> #------VAR-------------------------------------IMPORTANT TOOL:
>>> aStringVAR = tk.StringVar()
>>> aStringVAR.set( "_init_" )
>>> def aKeyPressEventHANDLER( anEvent ): # SIMPLE EventHANDLER,
# # also ignites remote responsive processes
... aTemplate = "[KEY]::{3: >10s}\n<s/n>::{0: >10d}\n(=@=)::{1: > 10d}\n^from::({5:})"
... sString = aTemplate.format( anEvent.serial,
... anEvent.time,
... anEvent.char,
... anEvent.keysym,
... anEvent.keysym_num,
... str(anEvent.widget )
... )
... aStringVAR.set( sString )
... print sString
...
>>> #----VAR_TRACER----------------------------------------[#1]
>>> def aVAR_TRACER_A( p1_quasiNAME, p2_indexOrEmptyString, p3_accessMODE ):
... print "aVAR_TRACER_A()-called::(on){0:} traced_event({1:})".format( str( p1_quasiNAME ), str( p3_accessMODE ) )
... # ###############=[A]#######
... # < do some task =[A] here >
... # ###############=[A]#######
... print "aVAR_TRACER_A() [{0:}]".format( str( root.globalgetvar( p1_quasiNAME ) ).replace( " ", "" ) )
...
>>> #----VAR_TRACER----------------------------------------[#2]
>>> def aVAR_TRACER_B( p1_quasiNAME, p2_indexOrEmptyString, p3_accessMODE ):
... print "aVAR_TRACER_B()-called::(on){0:} traced_event({1:})".format( str( p1_quasiNAME ), str( p3_accessMODE ) )
... # ###############=[B]#######
... # < do some task =[B] here >
... # ###############=[B]######
... print "aVAR_TRACER_B() [{0:}]".format( str( root.globalgetvar( p1_quasiNAME ) ).replace( " ", "" ) )
...
>>> #-----VAR_A_tracer_ID------------------------------"w" EVENT SNIFFER
>>> aTraceVAR_A_tracer_ID = aStringVAR.trace_variable( "w", aVAR_TRACER_A )
>>> #-----VAR_B_tracer_ID------------------------------"w" EVENT SNIFFER
>>> aTraceVAR_B_tracer_ID = aStringVAR.trace_variable( "w", aVAR_TRACER_B )
>>> #-----------tracer_ID values for ev. theirs resp. de-activation:
>>> aTraceVAR_A_tracer_ID
'3071960124LaVAR_TRACER_A'
>>> aTraceVAR_B_tracer_ID
'3071961284LaVAR_TRACER_B'
>>> #---.bind()-----------------------EventHANDLER with a system event <KeyPress>
>>> root.bind( "<KeyPress>", aKeyPressEventHANDLER ) # <-since here LIVE (!)
'3071841740LaKeyPressEventHANDLER'
>>> #------------------------------------------------^^^ since here, it went live
>>> # 1: having put a mouse on tk-window,
>>> # 2: set-focus by click
>>> # 3: started keys:
>>> # ( "a",
>>> # 6-on-<NumKeyPad>,
>>> # *-on-<NumKeyPad>
>>> # this happened "independently, at the same time" ( see time (=@=):: values )
>>>
aVAR_TRACER_B()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_B() [[KEY]::a<s/n>::832(=@=)::88486992^from::(.)]
aVAR_TRACER_A()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_A() [[KEY]::a<s/n>::832(=@=)::88486992^from::(.)]
[KEY]:: a
<s/n>:: 832
(=@=):: 88486992
^from::(.)
aVAR_TRACER_B()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_B() [[KEY]::KP_6<s/n>::832(=@=)::88509107^from::(.)]
aVAR_TRACER_A()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_A() [[KEY]::KP_6<s/n>::832(=@=)::88509107^from::(.)]
[KEY]:: KP_6
<s/n>:: 832
(=@=):: 88509107
^from::(.)
aVAR_TRACER_B()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_B() [[KEY]::KP_Multiply<s/n>::832(=@=)::88541180^from::(.)]
aVAR_TRACER_A()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_A() [[KEY]::KP_Multiply<s/n>::832(=@=)::88541180^from::(.)]
[KEY]::KP_Multiply
<s/n>:: 832
(=@=):: 88541180
^from::(.)
我的服务器有这个代码:
import time
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5000")
while True:
message = socket.recv()
socket.send(b"World")
print "sent"
while True:
print "done."
我有一个单独的客户端脚本,每当我发送一条消息时,它都会通过 zmq 向这个脚本发送一条消息。在服务器上(这段代码),如果我只有第一个 while True:,它会在我每次发送消息时打印 "sent",如果我只有第二个 while True:,它会打印 "done."不断地。但是,如果我同时放置两者,它永远不会打印完成(或者如果我切换他们的顺序并同时放置它们,当我发送消息时它永远不会打印 "sent"”)。
作为输出,我希望它连续打印 "done.",并在收到消息时打印 "sent"。所以像这样:
done.
done.
done.
done.
done.
sent
done.
lots more done....
基本上我希望两个循环 运行 连续且完全独立于彼此。
N.B。我曾尝试使用多处理(例如此处的第 3 个答案 How do I run two python loops concurrently?),但也无法使其正常工作。我试过如下:
import time
import zmq
from multiprocessing import Process
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5000")
i = time.time()
def zmq_loop():
while True:
message = socket.recv()
socket.send(b"World")
print "sent"
def done_loop():
global i
while True:
i2 = time.time()-i
if i2%2 == 0:
print "done."
if __name__ == "__main__":
Process(target=zmq_loop).start()
Process(target=done_loop).start()
正如昨天在 [CONCURRENT]
-处理在 python 中可以通过多种不同的方式在技术上实现,每种方式的成本都不同。
今天,让我们来看看另一种方法 - 使用一个框架,它的开发动机完全相同 - 具有自然的 [CONCURRENT]
-已经在 DNA 中的调度 - 最初旨在轻松编写和流畅操作复杂的 GUI 人机交互 (MMI)。
这个框架可能而且将会帮助你实现很多,因为事实上,它已经在完全相同的场景中得到了很多关注,在这些场景中,必须同时监控不止一件事:
欢迎使用 Tkinter
GUI 框架,我们仅将其用于智能并发操作的事件处理程序。
我多次感到非常惊讶,构建一个相当复杂的有限状态自动机 (FSA) 组合是多么容易,它可以顺利合作(FSA-s 的联盟),使用独立的工具,隔离操作(每个 FSA 的内部逻辑),但能够轻松地将信号/消息从一个 FSA 传播到另一个 FSA。是的,他们实际上可以在 1-event-source-FSA : N-consumer(s)-FSA(s)
在那里你可以创建(使用 ZeroMQ 始终以非阻塞方式)处理程序——一个 "sniffer"定期检查(最好通过超时控制的 .poll()
方法来 { NACK | POSACK }
任何要读取的内容)——另一个 "reader" 用于从 ZeroMQ Socket()
实例实际读取(由来自 "sniffer" 的 POSACK
信号触发,如前所述 - 另一个 "do-a-work-er" 对于任何其他可能希望操作的任务
Tkinter .mainloop()
方法是全局控制器,它为您编排肮脏的工作。
Tkinter 介导的代理协同处理的高级概念从 main()
开始,非常简单:
def main():
root = Tk() # INIT a Tk() instance
root.lift() # + make it visible
app = myApplication( root ) # SET ( [HERE] are all your app gems )
root.mainloop() # START the core event-handling orchestrator
Tkinter 可能看起来像一个充满各种 GUI 小工具的车库,与您的问题无关,但不要惊慌。
Tkinter 拥有非常适合您需求的出色工具。
using control variables 将用作在其他独立且明确未协调的参与者之间存储、发信号和传播值变化的手段(参考文献 "sniffer","reader"、"worker" 和任何其他...)
用于处理定时操作的工具 - 几乎是轻量级实时系统的形式,使用设置了接下来会发生什么的首选时间,
.mainloop()
-尚需牢记
明确指定的时间.after( thisAmountOfMILLISECONDS, callThisFUNCTION )
或自由.after_idle( callAlwaysThatFUNCTION )
.
使用这些已经很完美的工具,您确实不需要任何其他东西来解决您的任务。
所以剩下的只是原则上在你的创造力下如何重新使用这些智能工具。
一个小演示,
如何使两(3!)件事发生"at the same time independently"
让我们设置案例,当一个人想要同时处理(这里通过打印演示)几个独立的进程时。
>>> #-----------------------------------------------FAST MOCK-UP EXAMPLE
>>> import Tkinter as tk # python27
>>> root = tk.Tk()
>>> root.protocol( "WM_DELETE_WINDOW", root.quit() )
'3071841620Ldestroy'
>>> #------VAR-------------------------------------IMPORTANT TOOL:
>>> aStringVAR = tk.StringVar()
>>> aStringVAR.set( "_init_" )
>>> def aKeyPressEventHANDLER( anEvent ): # SIMPLE EventHANDLER,
# # also ignites remote responsive processes
... aTemplate = "[KEY]::{3: >10s}\n<s/n>::{0: >10d}\n(=@=)::{1: > 10d}\n^from::({5:})"
... sString = aTemplate.format( anEvent.serial,
... anEvent.time,
... anEvent.char,
... anEvent.keysym,
... anEvent.keysym_num,
... str(anEvent.widget )
... )
... aStringVAR.set( sString )
... print sString
...
>>> #----VAR_TRACER----------------------------------------[#1]
>>> def aVAR_TRACER_A( p1_quasiNAME, p2_indexOrEmptyString, p3_accessMODE ):
... print "aVAR_TRACER_A()-called::(on){0:} traced_event({1:})".format( str( p1_quasiNAME ), str( p3_accessMODE ) )
... # ###############=[A]#######
... # < do some task =[A] here >
... # ###############=[A]#######
... print "aVAR_TRACER_A() [{0:}]".format( str( root.globalgetvar( p1_quasiNAME ) ).replace( " ", "" ) )
...
>>> #----VAR_TRACER----------------------------------------[#2]
>>> def aVAR_TRACER_B( p1_quasiNAME, p2_indexOrEmptyString, p3_accessMODE ):
... print "aVAR_TRACER_B()-called::(on){0:} traced_event({1:})".format( str( p1_quasiNAME ), str( p3_accessMODE ) )
... # ###############=[B]#######
... # < do some task =[B] here >
... # ###############=[B]######
... print "aVAR_TRACER_B() [{0:}]".format( str( root.globalgetvar( p1_quasiNAME ) ).replace( " ", "" ) )
...
>>> #-----VAR_A_tracer_ID------------------------------"w" EVENT SNIFFER
>>> aTraceVAR_A_tracer_ID = aStringVAR.trace_variable( "w", aVAR_TRACER_A )
>>> #-----VAR_B_tracer_ID------------------------------"w" EVENT SNIFFER
>>> aTraceVAR_B_tracer_ID = aStringVAR.trace_variable( "w", aVAR_TRACER_B )
>>> #-----------tracer_ID values for ev. theirs resp. de-activation:
>>> aTraceVAR_A_tracer_ID
'3071960124LaVAR_TRACER_A'
>>> aTraceVAR_B_tracer_ID
'3071961284LaVAR_TRACER_B'
>>> #---.bind()-----------------------EventHANDLER with a system event <KeyPress>
>>> root.bind( "<KeyPress>", aKeyPressEventHANDLER ) # <-since here LIVE (!)
'3071841740LaKeyPressEventHANDLER'
>>> #------------------------------------------------^^^ since here, it went live
>>> # 1: having put a mouse on tk-window,
>>> # 2: set-focus by click
>>> # 3: started keys:
>>> # ( "a",
>>> # 6-on-<NumKeyPad>,
>>> # *-on-<NumKeyPad>
>>> # this happened "independently, at the same time" ( see time (=@=):: values )
>>>
aVAR_TRACER_B()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_B() [[KEY]::a<s/n>::832(=@=)::88486992^from::(.)]
aVAR_TRACER_A()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_A() [[KEY]::a<s/n>::832(=@=)::88486992^from::(.)]
[KEY]:: a
<s/n>:: 832
(=@=):: 88486992
^from::(.)
aVAR_TRACER_B()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_B() [[KEY]::KP_6<s/n>::832(=@=)::88509107^from::(.)]
aVAR_TRACER_A()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_A() [[KEY]::KP_6<s/n>::832(=@=)::88509107^from::(.)]
[KEY]:: KP_6
<s/n>:: 832
(=@=):: 88509107
^from::(.)
aVAR_TRACER_B()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_B() [[KEY]::KP_Multiply<s/n>::832(=@=)::88541180^from::(.)]
aVAR_TRACER_A()-called::(on)PY_VAR0 traced_event(w)
aVAR_TRACER_A() [[KEY]::KP_Multiply<s/n>::832(=@=)::88541180^from::(.)]
[KEY]::KP_Multiply
<s/n>:: 832
(=@=):: 88541180
^from::(.)