Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用0mq(ZeroMQ)同步两个简单python3脚本时出现死锁_Python_Synchronization_Deadlock_Zeromq_Low Latency - Fatal编程技术网

使用0mq(ZeroMQ)同步两个简单python3脚本时出现死锁

使用0mq(ZeroMQ)同步两个简单python3脚本时出现死锁,python,synchronization,deadlock,zeromq,low-latency,Python,Synchronization,Deadlock,Zeromq,Low Latency,当我尝试使用0mq(ZeroMQ)同步两个python3脚本时,我遇到了这种奇怪的死锁。这些脚本在数千次迭代中运行良好,但迟早它们都会停止并等待对方。我在Windows7上从不同的CMD窗口运行这两个脚本 我不明白为什么会出现这样的僵局这里会出什么问题? 脚本A: while (1): context = zmq.Context() socket = context.socket(zmq.REP) socket.bind('tcp://127.0.0.1:10001')

当我尝试使用0mq(
ZeroMQ
)同步两个python3脚本时,我遇到了这种奇怪的死锁。这些脚本在数千次迭代中运行良好,但迟早它们都会停止并等待对方。我在Windows7上从不同的CMD窗口运行这两个脚本

我不明白为什么会出现这样的僵局
这里会出什么问题?

脚本A:

while (1):
   context = zmq.Context()
   socket = context.socket(zmq.REP)
   socket.bind('tcp://127.0.0.1:10001')
   msg = socket.recv()                        # Waiting for script B to send done
   # ............................................................................
   # ... do something useful (takes only a few millisecs)
   # ............................................................................     
   context = zmq.Context()
   socket = context.socket(zmq.REQ)
   socket.connect('tcp://127.0.0.1:10002')
   socket.send_string("done")                 # Tell script B we are done
脚本B

while (1):
   # ............................................................................
   # ... do something useful (takes only a few millisecs)
   # ............................................................................
   context = zmq.Context()
   socket = context.socket(zmq.REQ)
   socket.connect('tcp://127.0.0.1:10001')
   socket.send_string("done")               # Tell script A we are done

   context = zmq.Context()
   socket = context.socket(zmq.REP)
   socket.bind('tcp://127.0.0.1:10002')
   msg = socket.recv()                      # Waiting for script A to send done

您应该只处理一次
上下文
套接字
创建,而不是每次迭代

此外,您还应该重用上下文(除非您打算从另一个上下文使用它) 线程)

这同样适用于第二个脚本

try:
    context = zmq.Context()
    rq_sck = context.socket(zmq.REQ)
    rq_sck.connect('tcp://127.0.0.1:10001')

    rep_sck = context.socket(zmq.REP)
    rep_sck.bind('tcp://127.0.0.1:10002')

    while (1):
        do something useful (takes only a few millisecs)

        rq_sck.send_string("done") # Tell script A we are done

        msg = rep_sck.recv() # Waiting for script A to send done
finally:
    rq_sck.close()
    rep_sck.close()
编辑:更新代码以调用
Socket.close()

自pyzmq版本14.3.0以来,
Socket.close()
Context.term()
不会自动调用 在垃圾收集期间,添加了正确关闭套接字的操作。

这不是死锁情况 当然,代码仍然需要一些注意

消除歧义:您的场景不会进入资源互锁状态,即死锁。是的,当然,您的代码会崩溃,但很可能不是由于
REQ/REP
死锁造成的(在有损网络
tcp:
传输类中可能会出现死锁)。发布的代码崩溃是由于非托管资源处理,而不是由于达到死锁/活锁的相互阻塞状态


如何修复它? 首先,假设您的超低延迟激励系统不允许重复实例化任何内容。这方面也有例外,但让我们从中受益

  • .Context()
    资源设置(或从外部调用继承)移出循环

  • 查看,您是否需要并且您的延迟限制允许您在每次循环运行中设置/拆除
    .socket()
    资源两次

  • 决定,一旦第一条消息在传输路径中丢失,您是否可以接受real
    REQ/REP
    死锁

  • 强制执行优雅的资源使用终止(
    .socket()
    -s,O/s
    端口#
    s,
    .Context()
    -s)。不要让它们永远挂在没有终端的地方,而要创造无限多的其他系统,这会破坏任何“故障恢复”系统。资源永远不是无限的

  • 设计以非阻塞方式发送信号和传输行为。这允许您检测和处理远程进程超时,并为本地补救/响应操作提供机会

  • 重新设计代码,使其达到您所需的安全代码级别(以下示例在分布式处理框架中24/7/365软实时控制无止境循环中工作几年,使用远程键盘和其他一些本地和远程诊断工具)


  • 生产等级代码缺少什么? 您的代码必须“预见”分布式系统的任何部分中可能出现的错误。是的,这很难,但却是必要的。您的远程节点(一个通信对手)停止响应、丢失消息、重新启动、由于O/S崩溃而暂停,这一切都是可以想象得到的(再加上一些您只会在运行中发现的令人不快的惊喜…)。这是另一个潘多拉的盒子,以涵盖在这个小帖子,这并不意味着它是没有必要的。这是你的救生衣

    尽可能以非阻塞方式进行设计,这样您就可以控制事件

    无论如何,总是以优雅的方式发布系统资源和
    .term()
    所有ZeroMQ
    .Context()
    实例--“整理”是一种公平的做法--无论是在现实生活中还是在代码帝国中

    # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    #NONSTOP RESPONDER RAW EXAMPLE:
    def aMiniRESPONDER( aTarget2Bind2_URL             = "tcp://A.B.C.D:8889",
                        anExternalPREDICTOR           = None,
                        anExternallyManagedZmqCONTEXT = None,
                        aSpreadMinSafetyMUL           = 3.0,
                        aSilentMODE                   = True
                        ):
       try: # RESOURCES LAYER
            # ... SETUP
            # ------------------------------------------------- .Context()
            # can setup a locally-managed context or re-use
            # anExternallyManagedZmqCONTEXT obtained upon a func Call
            aZmqCONTEXT   = anExternallyManagedZmqCONTEXT or zmq.Context( 1 )   
    
            # localhost:8887 [REP] ... remote [REQ] peer  .connect() + .send()
            aCtrlPORT_URL = "tcp://*:8887"                                      
    
            # localhost:8890 [PUB] ... remote [SUB] peers .connect() +
            # .subscribe + .recv( zmq.NOBLOCK ) ( MQL4 cannot .poll() so far ...)
            aSIGsPORT_URL = "tcp://*:8890"                                      
            aXmitPORT_URL = aTarget2Bind2_URL
    
            aListOfSOCKETs = []
    
            pass # -------------------------------------------------------------# ZMQ
            try: # -------------------------------------------------------------#
                # try: XmitPORT
                aXmitSOCKET = aZmqCONTEXT.socket( zmq.PAIR )
    
                # XmitPORT
                aXmitSOCKET.bind(      aXmitPORT_URL )                          
                aListOfSOCKETs.append( aXmitSOCKET )
            except:                                                             
                #    EXC: XmitPORT on Failure: GRACEFUL CLEARING XmitPORT
    
                msg =  "\nEXC. ZmqError({0:s}) on aXmitSOCKET setup / .bind( {1:s} )"
                print msg.format( repr( zmq.ZMQError() ), aTarget2Bind2_URL )
                raise ValueError( "ZMQ_EXC_EXIT @ XmitPORT SETUP" )
            pass # -------------------------------------------------------------# ZMQ
            try: # -------------------------------------------------------------#
                # try: CtrlPORT    
                # CtrlSOCKET [REP] .recv()s<--[REQ] + .send()s--> [REQ]
                aCtrlSOCKET = aZmqCONTEXT.socket( zmq.REP )                     
    
                # CtrlPORT <-REQ/REP means a remote peer [REQ] has to
                # .send()+.recv() before sending another CtrlCMD
                aCtrlSOCKET.bind(      aCtrlPORT_URL )                          
                aListOfSOCKETs.append( aCtrlSOCKET )
            except:                                                             
                # EXC: CtrlPORT on Failure: GRACEFUL CLEARING both CtrlPORT
                # and XmitPORT
                msg =  "\nEXC. ZmqError({0:s}) on aCtrlSOCKET setup / .bind( {1:s} )"
                print msg.format( repr( zmq.ZMQError() ), aCtrlPORT_URL )
                raise ValueError( "ZMQ_EXC_EXIT @ CtrlPORT SETUP" )
            pass # -------------------------------------------------------------# ZMQ
            try: # -------------------------------------------------------------#
                # try: SIGsPORT
    
                # SIGsPORT [PUB] .send()s--> [SUB]s
                aSIGsSOCKET= aZmqCONTEXT.socket( zmq.PUB  )                     
    
                # SIGsPORT -->  PUB/SUB means a remote peer(s) [SUB] .subscribe() + .recv()
                aSIGsSOCKET.bind(      aSIGsPORT_URL )                          
                aListOfSOCKETs.append( aSIGsSOCKET )
            except:                                                             
                # EXC: SIGsPORT on Failure: GRACEFUL CLEARING both CtrlPORT
                # and XmitPORT and SIGsPORT
                msg =  "\nEXC. ZmqError({0:s}) on aSIGsSOCKET setup / .bind( {1:s} )"
                print msg.format( repr( zmq.ZMQError() ), aSIGsPORT_URL )
                raise ValueError( "ZMQ_EXC_EXIT @ SIGsPORT SETUP" )
            pass # -------------------------------------------------------------# ZMQ
    
            # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
            # ... SETUP YOUR APPLICATION CODE
    
            try:     # APP LAYER ___________________________________________
               #           what you want to do
               #           here you go ...
    
            except:  # APP LAYER ___________________________________________
               #           handle EXCs
    
            finally: # APP LAYER ___________________________________________
               #           your own application post-mortem / pre-exit code
    
            # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
       except:  # RESOURCES LAYER .............................................
            # ... code shall handle it's own exceptions + externally caused events
    
       finally: # RESOURCES LAYER .............................................
            # ... always, ALWAYS gracefully exit ( avoid leakages and dirty things )
    
            [ allSOCKETs.setsockopt( zmq.LINGER, 0 ) for allSOCKETs in aListOfSOCKETs ]
            [ allSOCKETs.close( )                    for allSOCKETs in aListOfSOCKETs ]
    
            # --------------------------------------------------------------#
            # RESOURCES dismantled, may .term()
    
            # .TERM(), NOP otherwise
            if not ( aZmqCONTEXT is anExternallyManagedZmqCONTEXT ):        #
                     aZmqCONTEXT.term()                                     #
            return
    
    #/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    #不间断响应程序原始示例:
    定义aMiniRESPONDER(aTarget2Bind2_URL=”tcp://A.B.C.D:8889",
    anExternalPREDICTOR=无,
    anExternallyManagedZmqCONTEXT=None,
    aSpreadMinSafetyMUL=3.0,
    aSilentMODE=True
    ):
    try:#资源层
    # ... 设置
    #-------------------------------------------------------.Context()
    #可以设置本地管理的上下文或重复使用
    #在func调用时获得的外部ymanagedzmqcontext
    aZmqCONTEXT=anexternalymanagedzmqcontext或zmq.Context(1)
    #本地主机:8887[代表]。。。远程[REQ]对等连接()+发送()
    aCtrlPORT_URL=“tcp://*:8887”
    #本地主机:8890[发布]。。。远程[SUB]对等点连接()+
    #.subscribe+.recv(zmq.NOBLOCK)(到目前为止MQL4无法.poll())
    aSIGsPORT_URL=“tcp://*:8890”
    aXmitPORT_URL=aTarget2Bind2_URL
    aListOfSOCKETs=[]
    通过#---------------------------------------------#ZMQ
    试试看-------------------------------------------------------------#
    #尝试:XmitPORT
    aXmitSOCKET=aZmqCONTEXT.socket(zmq.PAIR)
    #XmitPORT
    aXmitSOCKET.bind(aXmitPORT\u URL)
    aListOfSOCKETs.append(aXmitSOCKET)
    除:
    #EXC:XmitPORT发生故障:正常清除XmitPORT
    msg=“\nEXC.ZmqError({0:s})在aXmitSOCKET setup/.bind({1:s})”上
    print msg.format(repr(zmq.ZMQError()),aTarget2Bind2_URL)
    提升值错误(“ZMQ\u EXC\u EXIT@XmitPORT SETUP”)
    通过#-
    
    # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    #NONSTOP RESPONDER RAW EXAMPLE:
    def aMiniRESPONDER( aTarget2Bind2_URL             = "tcp://A.B.C.D:8889",
                        anExternalPREDICTOR           = None,
                        anExternallyManagedZmqCONTEXT = None,
                        aSpreadMinSafetyMUL           = 3.0,
                        aSilentMODE                   = True
                        ):
       try: # RESOURCES LAYER
            # ... SETUP
            # ------------------------------------------------- .Context()
            # can setup a locally-managed context or re-use
            # anExternallyManagedZmqCONTEXT obtained upon a func Call
            aZmqCONTEXT   = anExternallyManagedZmqCONTEXT or zmq.Context( 1 )   
    
            # localhost:8887 [REP] ... remote [REQ] peer  .connect() + .send()
            aCtrlPORT_URL = "tcp://*:8887"                                      
    
            # localhost:8890 [PUB] ... remote [SUB] peers .connect() +
            # .subscribe + .recv( zmq.NOBLOCK ) ( MQL4 cannot .poll() so far ...)
            aSIGsPORT_URL = "tcp://*:8890"                                      
            aXmitPORT_URL = aTarget2Bind2_URL
    
            aListOfSOCKETs = []
    
            pass # -------------------------------------------------------------# ZMQ
            try: # -------------------------------------------------------------#
                # try: XmitPORT
                aXmitSOCKET = aZmqCONTEXT.socket( zmq.PAIR )
    
                # XmitPORT
                aXmitSOCKET.bind(      aXmitPORT_URL )                          
                aListOfSOCKETs.append( aXmitSOCKET )
            except:                                                             
                #    EXC: XmitPORT on Failure: GRACEFUL CLEARING XmitPORT
    
                msg =  "\nEXC. ZmqError({0:s}) on aXmitSOCKET setup / .bind( {1:s} )"
                print msg.format( repr( zmq.ZMQError() ), aTarget2Bind2_URL )
                raise ValueError( "ZMQ_EXC_EXIT @ XmitPORT SETUP" )
            pass # -------------------------------------------------------------# ZMQ
            try: # -------------------------------------------------------------#
                # try: CtrlPORT    
                # CtrlSOCKET [REP] .recv()s<--[REQ] + .send()s--> [REQ]
                aCtrlSOCKET = aZmqCONTEXT.socket( zmq.REP )                     
    
                # CtrlPORT <-REQ/REP means a remote peer [REQ] has to
                # .send()+.recv() before sending another CtrlCMD
                aCtrlSOCKET.bind(      aCtrlPORT_URL )                          
                aListOfSOCKETs.append( aCtrlSOCKET )
            except:                                                             
                # EXC: CtrlPORT on Failure: GRACEFUL CLEARING both CtrlPORT
                # and XmitPORT
                msg =  "\nEXC. ZmqError({0:s}) on aCtrlSOCKET setup / .bind( {1:s} )"
                print msg.format( repr( zmq.ZMQError() ), aCtrlPORT_URL )
                raise ValueError( "ZMQ_EXC_EXIT @ CtrlPORT SETUP" )
            pass # -------------------------------------------------------------# ZMQ
            try: # -------------------------------------------------------------#
                # try: SIGsPORT
    
                # SIGsPORT [PUB] .send()s--> [SUB]s
                aSIGsSOCKET= aZmqCONTEXT.socket( zmq.PUB  )                     
    
                # SIGsPORT -->  PUB/SUB means a remote peer(s) [SUB] .subscribe() + .recv()
                aSIGsSOCKET.bind(      aSIGsPORT_URL )                          
                aListOfSOCKETs.append( aSIGsSOCKET )
            except:                                                             
                # EXC: SIGsPORT on Failure: GRACEFUL CLEARING both CtrlPORT
                # and XmitPORT and SIGsPORT
                msg =  "\nEXC. ZmqError({0:s}) on aSIGsSOCKET setup / .bind( {1:s} )"
                print msg.format( repr( zmq.ZMQError() ), aSIGsPORT_URL )
                raise ValueError( "ZMQ_EXC_EXIT @ SIGsPORT SETUP" )
            pass # -------------------------------------------------------------# ZMQ
    
            # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
            # ... SETUP YOUR APPLICATION CODE
    
            try:     # APP LAYER ___________________________________________
               #           what you want to do
               #           here you go ...
    
            except:  # APP LAYER ___________________________________________
               #           handle EXCs
    
            finally: # APP LAYER ___________________________________________
               #           your own application post-mortem / pre-exit code
    
            # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
       except:  # RESOURCES LAYER .............................................
            # ... code shall handle it's own exceptions + externally caused events
    
       finally: # RESOURCES LAYER .............................................
            # ... always, ALWAYS gracefully exit ( avoid leakages and dirty things )
    
            [ allSOCKETs.setsockopt( zmq.LINGER, 0 ) for allSOCKETs in aListOfSOCKETs ]
            [ allSOCKETs.close( )                    for allSOCKETs in aListOfSOCKETs ]
    
            # --------------------------------------------------------------#
            # RESOURCES dismantled, may .term()
    
            # .TERM(), NOP otherwise
            if not ( aZmqCONTEXT is anExternallyManagedZmqCONTEXT ):        #
                     aZmqCONTEXT.term()                                     #
            return