如何使用连接在不同进程中调用函数

2024-05-06 16:22:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我想使用Python实现某种类型的oft客户机-服务器连接,并且对多处理相当陌生。基本上,我有一个类“Manager”,它继承自multiprocessing.Process并管理从客户端到不同数据源的连接。这个过程有一些函数,比如“get_value(key)”,应该返回key数据源的值。现在,由于我想让它异步运行,我不能简单地从我的客户机进程调用这个函数

到目前为止,我的想法是使用管道连接客户端和管理器进程,然后从客户端向管理器发送消息以执行此功能。我可以通过管道发送一个列表来实现这一点,其中第一个元素是函数名,其余元素是实际函数的参数,例如,['get_value','datasource1']。然后,该进程将接收该消息并通过管道将返回值发送给客户端。这看起来像这样:

from multiprocessing import Process, Pipe
import time

class Manager(Process):
    def __init__(self, connection):
        super(Process, self).__init__()
        self.connection = connection

    def run(self):
        while True:
            if self.connection.poll():
                msg = self.connection.recv()
                self.call_function(msg[0], msg[:])

    def call_function(self, name, *args):
        print('Function Called with %s' % name)
        return_val = getattr(self, name)(*args)
        self.connection.send(return_val)

    def get_value(self, key):
        return 1.0

虽然我想这会奏效,但我对这个解决方案不是很满意。尤其是字符串方法调用函数似乎非常容易出错。有没有更优雅的方式来请求在Python中执行函数


Tags: key函数nameself客户端get客户机return
1条回答
网友
1楼 · 发布于 2024-05-06 16:22:39

总的来说,我认为你的方法是好的(当然,还有其他方法可以做同样的事情,但你的一般方法没有错)

这就是说,我将稍微改变设计,添加一个“路由”组件:考虑一些逻辑,以某种方式限制客户端可以发送的“命令”,以及命令和“处理程序”之间的挂钩,即处理它们的函数。基本上考虑Web框架路由(如果您熟悉这个概念的话)

从设计的灵活性、错误检测和安全性(例如,您不希望客户端在您的Manager上调用['__del__'])方面来说,这都是一个好主意

在非常基本的形式下,router可以是将命令映射到类方法的字典:

class Manager(Process):
    def __init__(self, connection):
      super(Process, self).__init__()
      self.connection = connection

      self.routes = {'do_action': self._do_action,
                     'do_other_action': some_callable,
                     'ping': lambda args: args}  # <- as long as it's callable and has the right signature...

  def call_function(self, name, *args):
      try:
          handler = self.routes[name]
      except KeyError:
          return self._error_reply('{} is not a valid command'.format(name))

      try:
          return_val = handler(*args)  # handler functions will need to throw something if arguments are wrong...
      except ValueError as e:
          return self._error_reply('Invalid command arguments: {}'.format(str(e)))
      except Exception as e:
          # This is your catch-all "internal server error" handler
          return self._error_reply(str(e))

      self.connection.send(return_val)

这当然只是一个方法的例子。您需要以任何适合您的方式实现_error_reply()

您可以通过创建Router类并将其作为依赖项传递给管理器来扩展它,从而使其更加灵活。您可能还想考虑使您的管理器成为一个独立的东西,而不是Process的子类(因为您可能希望运行它,而不管它是否在子流程中—例如在测试中)

顺便说一句,有一些框架可以实现各种复杂度和灵活性(Thrift,ZeroMQ,…),但是如果你想做一些简单的事情,并且学习,在我看来,自己做是一个很好的选择

相关问题 更多 >