正确断开多进程远程管理器

5 投票
2 回答
3128 浏览
提问于 2025-04-16 20:29

当你使用 multiprocessing 的管理器对象来创建一个服务器,并且想要远程连接到这个服务器时,客户端需要保持与远程服务器的连接。如果服务器在客户端关闭之前就消失了,客户端会一直尝试连接到服务器的地址,直到成功为止。

我在客户端代码中遇到了死锁的问题,客户端在服务器消失后尝试退出,但我的客户端进程始终无法退出。

如果我在服务器关闭之前删除我的远程对象和客户端的管理器,进程就会正常退出,但在使用完客户端的管理器对象和远程对象后立即删除它们并不是一个理想的做法。

这样做是我能做到的最好方式吗?有没有其他(更合适的)方法可以断开与远程管理器对象的连接?有没有办法在服务器关闭后或者连接丢失后干净利落地退出客户端?

我知道 socket.setdefaulttimeout 在多进程中不起作用,但有没有办法专门为多进程模块设置连接超时?这是我遇到问题的代码:

from multiprocessing.managers import BaseManager
m = BaseManager(address=('my.remote.server.dns', 50000), authkey='mykey')
# this next line hangs forever if my server is not running or gets disconnected
m.connect()

更新 这在多进程中是有问题的。连接超时需要在套接字层面处理(而且套接字需要是非阻塞的才能做到这一点),但非阻塞套接字会破坏多进程的功能。如果远程服务器不可用,就无法处理放弃连接的情况。

2 个回答

0

这对你有帮助吗?

#### TEST_JOIN_TIMEOUT

def join_timeout_func():
    print '\tchild sleeping'
    time.sleep(5.5)
    print '\n\tchild terminating'

def test_join_timeout():
    p = multiprocessing.Process(target=join_timeout_func)
    p.start()

    print 'waiting for process to finish'

    while 1:
        p.join(timeout=1)
        if not p.is_alive():
            break
        print '.',
        sys.stdout.flush()

(摘自 Python 16.6 页)

通常,超时会在某个循环中进行测试。

1

有没有办法专门为多进程模块设置连接超时?

可以,但这有点像是变通的方法。我希望有更懂 Python 的人能改进这个答案。多进程的超时设置在 multiprocessing/connection.py 文件中定义:

# A very generous timeout when it comes to local connections...
CONNECTION_TIMEOUT = 20.
...
def _init_timeout(timeout=CONNECTION_TIMEOUT):
        return time.time() + timeout

具体来说,我让它工作的方式是通过修改 _init_timeout 方法,代码如下:

import sys
import time

from multiprocessing import managers, connection

def _new_init_timeout():
    return time.time() + 5

sys.modules['multiprocessing'].__dict__['managers'].__dict__['connection']._init_timeout = _new_init_timeout
from multiprocessing.managers import BaseManager
m = BaseManager(address=('somehost', 50000), authkey='secret')
m.connect()

这里的 5 是新的超时时间。如果有更简单的方法,我相信会有人指出来。如果没有,这可能可以作为一个功能请求提交给多进程开发团队。我觉得设置超时这样简单的事情应该比这更容易。不过,他们可能有自己的理由不在 API 中提供超时设置。

希望这对你有帮助。

撰写回答