def call(self, function, args=[], kwargs={}, proxy_id=None, wait=True): # Step 1: Send Request request = Request(generate_id(), proxy_id, function, args, kwargs) if wait: event = Event() with self._lock: self._pending[request.id] = event self._queue.appendleft(request) # Step 2: Wait for Response if wait: event.wait() else: return # Step 3: Process Response with self._lock: response = self._pending.pop(request.id, None) if not isinstance(response, Response): raise RuntimeError('Dispatcher stored invalid response') elif response.exception: raise response.exception elif isinstance(response.return_value, ProxyHandle): proxy_handle = response.return_value try: proxy_class = self._consumed_classes[proxy_handle.obj_type] except KeyError: logger.info("Recieved proxy_class for unexpected type %s" % proxy_handle.obj_type) else: return proxy_class(self, proxy_handle.id, proxy_handle.exposed) else: return response.return_value
def set_state(self, state): with self._lock: if state > self.state: self._state = state self._queue.append(DispatcherState(state)) # head of line logger.info("Changing state to %d" % state) elif state == self.state: pass else: raise ValueError('Invalid state progression')
def _write_once(self, conn): if not self.alive(): return try: msg = self._queue.pop() except IndexError: return try: if isinstance(msg, DispatcherState) or self.state is State.RUNNING: conn.send(msg) else: logger.info("Skipping outgoing message %s" % repr(msg)) except IOError: self.state = State.TERMINATED except Exception as exception: # Most likely a PicklingError if hasattr(msg, 'id'): response = Response(msg.id, exception, None) self._process_response(response)
def _read_once(self, conn, timeout=0): if not self.alive() or not conn.poll(timeout): return try: msg = conn.recv() except EOFError: self.state = State.TERMINATED if isinstance(msg, Request) and self.state is State.RUNNING: response = self._process_request(msg) if response: self._queue.appendleft(response) elif isinstance(msg, Response) and self.state is State.RUNNING: self._process_response(msg) elif isinstance(msg, DispatcherState): if self.state is State.STARTUP and msg.state is State.STARTUP: self.state = State.RUNNING elif msg.state is State.SHUTDOWN: self.state = msg.state else: logger.info("Skipping incoming message %s" % repr(msg)) return True
def main(): parent_conn, child_conn = Pipe() p = Process(target=child, args=(child_conn,)) p.start() dispatch = Dispatcher(parent_conn) dispatch.consume("Foo") dispatch.consume("StaticFoo") dispatch.start() from multiprocessing.util import Finalize Finalize(dispatch, dispatch.shutdown, exitpriority=10) baz = dispatch.StaticFoo() baz.test() bar = dispatch.Foo() try: bar.tester() except AttributeError: print "Attribute Error Thrown!" else: assert False, "Should have thrown an exception" try: bar.test(True) except TypeError: print "Type Error Thrown!" else: assert False, "Should have thrown an exception" foo = dispatch.StaticFoo() count = 0 while count < 3: count = foo.test() logger.info("Count: %d" % count) print count time.sleep(0.25)
def test(self): with self.lock: self.count += 1 logger.info("Count: %d" % self.count) return self.count