def testBatchOneway(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone(batch.delay(1)) # a delay shouldn't matter with oneway self.assertIsNone(batch.multiply(3, 4)) begin = time.time() results = batch(oneway=True) duration = time.time() - begin self.assertTrue(duration < 0.1, "oneway batch with delay should return almost immediately") self.assertIsNone(results)
def testBatchProxy(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone(batch.divide(999, 3)) self.assertIsNone(batch.ping()) self.assertIsNone(batch.divide(999, 0)) # force an exception here self.assertIsNone(batch.multiply(3, 4)) # this call should not be performed after the error results = batch() self.assertEqual(42, next(results)) self.assertEqual(333, next(results)) self.assertIsNone(next(results)) self.assertRaises(ZeroDivisionError, next, results) # 999//0 should raise this error self.assertRaises(StopIteration, next, results) # no more results should be available after the error
def testBatchOneway(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone( batch.delay(1)) # a delay shouldn't matter with oneway self.assertIsNone(batch.multiply(3, 4)) begin = time.time() results = batch(oneway=True) duration = time.time() - begin self.assertTrue( duration < 0.1, "oneway batch with delay should return almost immediately") self.assertIsNone(results)
def testPyroTracebackBatch(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.divide(999, 0)) # force an exception here results = batch() try: next(results) self.fail("expected error") except ZeroDivisionError: # going to check if the magic pyro traceback attribute is available for batch methods too tb = "".join(Pyro4.util.getPyroTraceback()) self.assertIn("Remote traceback:", tb) # validate if remote tb is present self.assertIn("ZeroDivisionError", tb) # the error self.assertIn("return x // y", tb) # the statement self.assertRaises(StopIteration, next, results) # no more results should be available after the error
def testBatchAsync(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone(batch.delay(1)) # a delay shouldn't matter with async self.assertIsNone(batch.multiply(3, 4)) begin = time.time() asyncresult = batch(async=True) duration = time.time() - begin self.assertTrue(duration < 0.1, "async batch with delay should return almost immediately") results = asyncresult.value self.assertEqual(42, next(results)) self.assertEqual("slept 1 seconds", next(results)) self.assertEqual(12, next(results)) self.assertRaises(StopIteration, next, results) # no more results should be available
def screen(self, start, width): dr = width / self.res_x di = dr * (self.res_x / self.res_y) di *= 0.8 # aspect ratio correction self.num_lines_ready = 0 self.all_lines_ready.clear() self.result = ["?"] * self.res_y servers = [Pyro4.batch(proxy) for proxy in self.mandels] for i in range(self.res_y): server = servers[i % len(servers)] server.calc_line(start, self.res_x, i * di, dr, i) for batch in servers: batch(async=True).then(self.batch_result) self.all_lines_ready.wait(timeout=5) return "\n".join(self.result)
def screen(self, start, width): dr = width / self.res_x di = dr*(self.res_x/self.res_y) di *= 0.8 # aspect ratio correction self.num_lines_ready = 0 self.all_lines_ready.clear() self.result = ["?"] * self.res_y servers = [Pyro4.batch(proxy) for proxy in self.mandels] for i in range(self.res_y): server = servers[i % len(servers)] server.calc_line(start, self.res_x, i*di, dr, i) for batch in servers: batch(asynchronous=True).then(self.batch_result) self.all_lines_ready.wait(timeout=5) return "\n".join(self.result)
def return_homepage(environ, start_response): try: nameserver = get_nameserver(hmac=pyro_app.hmac_key) except Pyro4.errors.NamingError as x: print("Name server error:", x) start_response('500 Internal Server Error', [('Content-Type', 'text/plain')]) return [ b"Cannot connect to the Pyro name server. Is it running? Refresh page to retry." ] start_response('200 OK', [('Content-Type', 'text/html')]) nslist = [ "<table><tr><th>Name</th><th>methods</th><th>attributes (zero-param methods)</th></tr>" ] names = sorted(list(nameserver.list(regex=pyro_app.ns_regex).keys())[:10]) with Pyro4.batch(nameserver) as nsbatch: for name in names: nsbatch.lookup(name) for name, uri in zip(names, nsbatch()): attributes = "-" try: with Pyro4.Proxy(uri) as proxy: proxy._pyroHmacKey = pyro_app.hmac_key proxy._pyroBind() methods = " ".join(proxy._pyroMethods) or "-" attributes = [ "<a href=\"{name}/{attribute}\" onclick=\"pyro_call('{name}','{attribute}'); return false;\">{attribute}</a>" .format(name=name, attribute=attribute) for attribute in proxy._pyroAttrs ] attributes = " ".join(attributes) or "-" except Pyro4.errors.PyroError as x: stderr = environ["wsgi.errors"] print("ERROR getting metadata for {0}:".format(uri), file=stderr) traceback.print_exc(file=stderr) methods = "??error:%s??" % str(x) nslist.append( "<tr><td><a href=\"{name}/$meta\" onclick=\"pyro_call('{name}','$meta'); return false;\">{name}</a></td><td>{methods}</td><td>{attributes}</td></tr>" .format(name=name, methods=methods, attributes=attributes)) nslist.append("</table>") index_page = index_page_template.format( ns_regex=pyro_app.ns_regex, name_server_contents_list="".join(nslist), pyro_version=Pyro4.constants.VERSION, hostname=environ["SERVER_NAME"]) return [index_page.encode("utf-8")]
def testBatchProxy(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone(batch.divide(999, 3)) self.assertIsNone(batch.ping()) self.assertIsNone(batch.divide(999, 0)) # force an exception here self.assertIsNone(batch.multiply( 3, 4)) # this call should not be performed after the error results = batch() self.assertEqual(42, next(results)) self.assertEqual(333, next(results)) self.assertIsNone(next(results)) self.assertRaises(ZeroDivisionError, next, results) # 999//0 should raise this error self.assertRaises( StopIteration, next, results) # no more results should be available after the error
def testPyroTracebackBatch(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.divide(999, 0)) # force an exception here results = batch() try: next(results) self.fail("expected error") except ZeroDivisionError: # going to check if the magic pyro traceback attribute is available for batch methods too tb = "".join(Pyro4.util.getPyroTraceback()) self.assertIn("Remote traceback:", tb) # validate if remote tb is present self.assertIn("ZeroDivisionError", tb) # the error self.assertIn("return x // y", tb) # the statement self.assertRaises( StopIteration, next, results) # no more results should be available after the error
def testBatchAsync(self): with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone( batch.delay(1)) # a delay shouldn't matter with async self.assertIsNone(batch.multiply(3, 4)) begin = time.time() asyncresult = batch(async=True) duration = time.time() - begin self.assertTrue( duration < 0.1, "async batch with delay should return almost immediately") results = asyncresult.value self.assertEqual(42, next(results)) self.assertEqual("slept 1 seconds", next(results)) self.assertEqual(12, next(results)) self.assertRaises(StopIteration, next, results) # no more results should be available
def testBatchAsyncCallchain(self): class FuncHolder(object): count = AtomicCounter() def function(self, values): result = [value + 1 for value in values] self.count.incr() return result with Pyro4.core.Proxy(self.objectUri) as p: batch = Pyro4.batch(p) self.assertIsNone(batch.multiply(7, 6)) self.assertIsNone(batch.multiply(3, 4)) result = batch(async=True) holder = FuncHolder() result.then(holder.function).then(holder.function) value = result.value self.assertTrue(result.ready) self.assertEqual([44, 14], value) self.assertEqual(2, holder.count.value())
def return_homepage(environ, start_response): try: nameserver = get_nameserver(hmac=pyro_app.hmac_key) except Pyro4.errors.NamingError as x: print("Name server error:", x) start_response('500 Internal Server Error', [('Content-Type', 'text/plain')]) return [b"Cannot connect to the Pyro name server. Is it running? Refresh page to retry."] start_response('200 OK', [('Content-Type', 'text/html')]) nslist = ["<table><tr><th>Name</th><th>methods</th><th>attributes (zero-param methods)</th></tr>"] names = sorted(list(nameserver.list(regex=pyro_app.ns_regex).keys())[:10]) with Pyro4.batch(nameserver) as nsbatch: for name in names: nsbatch.lookup(name) for name, uri in zip(names, nsbatch()): attributes = "-" try: with Pyro4.Proxy(uri) as proxy: proxy._pyroHmacKey = pyro_app.hmac_key proxy._pyroBind() methods = " ".join(proxy._pyroMethods) or "-" attributes = ["<a href=\"{name}/{attribute}\" onclick=\"pyro_call('{name}','{attribute}'); return false;\">{attribute}</a>" .format(name=name, attribute=attribute) for attribute in proxy._pyroAttrs] attributes = " ".join(attributes) or "-" except Pyro4.errors.PyroError as x: stderr = environ["wsgi.errors"] print("ERROR getting metadata for {0}:".format(uri), file=stderr) traceback.print_exc(file=stderr) methods = "??error:%s??" % str(x) nslist.append( "<tr><td><a href=\"{name}/$meta\" onclick=\"pyro_call('{name}','$meta'); return false;\">{name}</a></td><td>{methods}</td><td>{attributes}</td></tr>" .format(name=name, methods=methods, attributes=attributes)) nslist.append("</table>") index_page = index_page_template.format(ns_regex=pyro_app.ns_regex, name_server_contents_list="".join(nslist), pyro_version=Pyro4.constants.VERSION, hostname=environ["SERVER_NAME"]) return [index_page.encode("utf-8")]
total+=p.add(10,20) p.printmessage("end of normal calls") assert total==(NUMBER_OF_LOOPS*(7*6 + 10+20)) # check duration=time.time()-begin print("that took {0:.2f} seconds ({1:.0f} calls/sec)".format(duration, NUMBER_OF_LOOPS*2.0/duration)) duration_normal=duration # Now we do the same loop of N remote calls but this time we use # the batched calls proxy. It collects all calls and processes them # in a single batch. For many subsequent calls on the same proxy this # is much faster than doing all calls individually. # (but it has a few limitations and requires changes to your code) print("\nBatched remote calls...") begin=time.time() batch=Pyro4.batch(p) # get a batched call proxy for 'p' batch.printmessage("beginning batch #1") for i in range(NUMBER_OF_LOOPS): batch.multiply(7,6) # queue a call, note that it returns 'None' immediately batch.add(10,20) # queue a call, note that it returns 'None' immediately batch.printmessage("end of batch #1") print("processing the results...") total=0 result=batch() # execute the batch of remote calls, it returns a generator that produces all results in sequence for r in result: total+=r duration=time.time()-begin assert total==(NUMBER_OF_LOOPS*(7*6 + 10+20)) # check print("total time taken {0:.2f} seconds ({1:.0f} calls/sec)".format(duration, NUMBER_OF_LOOPS*2.0/duration//100*100)) print("batched calls were {0:.1f} times faster than normal remote calls".format(duration_normal/duration))
if sys.version_info<(3,0): input=raw_input def asyncFunction(values): results=[value+1 for value in values] print(">>> async batch function called, returning:",results) return results uri=input("enter async server object uri: ").strip() proxy=Pyro4.Proxy(uri) print("\n* batch async call:") batch=Pyro4.batch(proxy) batch.divide(100,5) batch.divide(99,9) batch.divide(555,2) print("getting results...") asyncresults = batch(async=True) # returns immediately print("result value available?",asyncresults.ready) # prints False because the server is still 'busy' print("client can do other stuff here.") time.sleep(2) print("such as sleeping ;-)") time.sleep(2) print("sleeping some more, batch takes a while") time.sleep(2) print("getting result values...(will block until available)") results=asyncresults.value # blocks until the result is available print("resultvalues=",list(results))
total += p.add(10, 20) p.printmessage("end of normal calls") assert total == (NUMBER_OF_LOOPS * (7 * 6 + 10 + 20)) # check duration = time.time() - begin print("that took {0:.2f} seconds ({1:.0f} calls/sec)".format( duration, NUMBER_OF_LOOPS * 2.0 / duration)) duration_normal = duration # Now we do the same loop of N remote calls but this time we use # the batched calls proxy. It collects all calls and processes them # in a single batch. For many subsequent calls on the same proxy this # is much faster than doing all calls individually. # (but it has a few limitations and requires changes to your code) print("\nBatched remote calls...") begin = time.time() batch = Pyro4.batch(p) # get a batched call proxy for 'p' batch.printmessage("beginning batch #1") for i in range(NUMBER_OF_LOOPS): batch.multiply(7, 6) # queue a call, note that it returns 'None' immediately batch.add(10, 20) # queue a call, note that it returns 'None' immediately batch.printmessage("end of batch #1") print("processing the results...") total = 0 result = batch( ) # execute the batch of remote calls, it returns a generator that produces all results in sequence for r in result: total += r duration = time.time() - begin assert total == (NUMBER_OF_LOOPS * (7 * 6 + 10 + 20)) # check print("total time taken {0:.2f} seconds ({1:.0f} calls/sec)".format(
if sys.version_info < (3, 0): input = raw_input def asyncFunction(values): results = [value + 1 for value in values] print(">>> async batch function called, returning:", results) return results uri = input("enter async server object uri: ").strip() proxy = Pyro4.Proxy(uri) print("\n* batch async call:") batch = Pyro4.batch(proxy) batch.divide(100, 5) batch.divide(99, 9) batch.divide(555, 2) print("getting results...") asyncresults = batch(asynchronous=True) # returns immediately print("result value available?", asyncresults.ready) # prints False because the server is still 'busy' print("client can do other stuff here.") time.sleep(2) print("such as sleeping ;-)") time.sleep(2) print("sleeping some more, batch takes a while") time.sleep(2) print("getting result values...(will block until available)") results = asyncresults.value # blocks until the result is available