diff --git a/src/Test/TestNoparallel.py b/src/Test/TestNoparallel.py index 736bf4ea..27528dae 100644 --- a/src/Test/TestNoparallel.py +++ b/src/Test/TestNoparallel.py @@ -14,6 +14,13 @@ class ExampleClass(object): self.counted += 1 return "counted:%s" % i + @util.Noparallel(queue=True, ignore_class=True) + def countQueue(self, num=5): + for i in range(1, num+1): + time.sleep(0.01) + self.counted += 1 + return "counted:%s" % i + @util.Noparallel(blocking=False) def countNoblocking(self, num=5): for i in range(1, num+1): @@ -57,3 +64,34 @@ class TestNoparallel: obj1.countNoblocking().join() # Allow again and wait until finishes assert obj1.counted == 10 + + def testQueue(self): + obj1 = ExampleClass() + + threads = [ + gevent.spawn(obj1.countQueue), + gevent.spawn(obj1.countQueue), + gevent.spawn(obj1.countQueue) + ] + gevent.joinall(threads) + + assert obj1.counted == 15 # Calls should be executed sequentially + + def testIngoreClass(self): + obj1 = ExampleClass() + obj2 = ExampleClass() + + threads = [ + gevent.spawn(obj1.countQueue), + gevent.spawn(obj1.countQueue), + gevent.spawn(obj1.countQueue), + gevent.spawn(obj2.countQueue), + gevent.spawn(obj2.countQueue) + ] + s = time.time() + gevent.joinall(threads) + assert obj1.counted == 15 + assert obj2.counted == 10 + + taken = time.time() - s + assert taken >= 0.25 # Every count takes 0.05sec diff --git a/src/util/Noparallel.py b/src/util/Noparallel.py index d194526b..0ae9da68 100644 --- a/src/util/Noparallel.py +++ b/src/util/Noparallel.py @@ -4,14 +4,18 @@ import time class Noparallel(object): # Only allow function running once in same time - def __init__(self, blocking=True, ignore_args=False): + def __init__(self, blocking=True, ignore_args=False, ignore_class=False, queue=False): self.threads = {} self.blocking = blocking # Blocking: Acts like normal function else thread returned + self.queue = queue self.ignore_args = ignore_args + self.ignore_class = ignore_class def __call__(self, func): def wrapper(*args, **kwargs): - if self.ignore_args: + if self.ignore_class: + key = func # Unique key only by function and class object + elif self.ignore_args: key = (func, args[0]) # Unique key only by function and class object else: key = (func, tuple(args), str(kwargs)) # Unique key for function including parameters @@ -19,7 +23,11 @@ class Noparallel(object): # Only allow function running once in same time thread = self.threads[key] if self.blocking: thread.join() # Blocking until its finished - return thread.value # Return the value + if self.queue: + return wrapper(*args, **kwargs) # Run again + else: + return thread.value # Return the value + else: # No blocking if thread.ready(): # Its finished, create a new thread = gevent.spawn(func, *args, **kwargs)