0

对于我们新的开放实验室设备自动化标准(https://gitlab.com/SiLA2/sila_python),我们希望以两种模式运行设备(=gRPC 服务器):模拟模式和真实模式(具有相同的设置远程调用,但在第一种情况下,它应该只返回模拟响应,在第二种情况下它应该与硬件通信。

我的第一个想法是在单独的模块中创建两个几乎相同的 gRPC 服务程序 python 类,如下例所示:

hello_sim.py中:

class SayHello(SayHello_pb2_grpc.SayHelloServicer):
  #... implementation of the simulation servicer
  def SayHello(self, request, context):
  # simulation code ...
  return SayHello_pb2.SayHello_response("simulation")

hello_real.py中:

class SayHello(SayHello_pb2_grpc.SayHelloServicer):
  #... implementation of the real servicer
  def SayHello(self, request, context):
  # real hardware code
  return SayHello_pb2.SayHello_response("real")

然后,在 server.py 中创建 gRPC 服务器后,我可以通过在 gRPC 服务器上重新注册 servcier 来在模拟和实模式之间切换,例如:

服务器.py

# imports, init ...

grpc_server = GRPCServer(ThreadPoolExecutor(max_workers=10)) 

sh_sim = SayHello_sim.SayHello()
sh_real = SayHello_real.SayHello()

SayHello_pb2_grpc.add_SayHelloServicer_to_server(sh_sim, grpc_server)

grpc_server.run()

# ..... and later, still while the same grpc server is running, re-register, like

SayHello_pb2_grpc.add_SayHelloServicer_to_server(sh_real, grpc_server)

能够调用真正的硬件代码;或通过交换对服务对象的引用,例如:

# imports, init ...

grpc_server = GRPCServer(ThreadPoolExecutor(max_workers=10)) 

sh_sim = SayHello_sim.SayHello()
sh_real = SayHello_real.SayHello()

sh_current = sh_sim

SayHello_pb2_grpc.add_SayHelloServicer_to_server(sh_current , grpc_server)

grpc_server.run()

# ..... and then later, still while the same grpc server is running, re-register the real Servicer, like

sh_current = sh_real    
#  so that the server would just use the other servicer object for the next calls ...

但是这两种策略都不起作用:(

从 gRPC 客户端以模拟模式调用服务器时,我希望它应该回复(根据示例):“模拟”

gRPC_client.py

# imports, init ....

response = self.SayHello_stub.SayHello()
print(response)
>'simulation'

并在切换到实模式(通过任何机制)“真实”之后:

# after switching to real mode ...
response = self.SayHello_stub.SayHello()
print(response)
>'real'

在不完全关闭 gRPC 服务器(以及失去与客户端的连接)的情况下实现这种模式切换的最简洁和优雅的解决方案是什么?

非常感谢您提前提供的帮助!

PS:(关闭 gRPC 服务器并重新注册当然可以,但这不是我们想要的。)

4

1 回答 1

0

我的一位好心同事给了我一个很好的建议:可以使用依赖注入概念(s. https://en.wikipedia.org/wiki/Dependency_injection),比如:

class SayHello(pb2_grpc.SayHelloServicer):
    def inject_implementation(SayHelloImplmentation):
      self.implementation = SayHelloImplementation;

   def SayHello(self, request, context):
      return self.implementation.sayHello(request, context)

有关完整示例,请参阅 https://gitlab.com/SiLA2/sila_python/tree/master/examples/simulation_real_mode_demo

于 2019-01-23T11:05:19.160 回答