I have this code, whose purpose is to dedupe requests.
def dedup_requests(f):
pending = {}
@functools.wraps(f)
def wrapped(*args, **kwargs):
key = _make_call_key(args, kwargs)
if key not in pending:
pending[key] = gevent.spawn(f, *args, **kwargs)
result = pending[key].get()
if key in pending:
del pending[key]
return result
return wrapped
I suspect it is causing a deadlock somehow (this happens once in awhile, and I can't reproduce it).
It happens both when using threading and gevent.
Is the recurring use of get
allowed?
Can this code even produce a deadlock when threading is not involved?
Note that it runs under other gevent tasks, so spawned tasks might spawn additional tasks, in case that's an issue.
Though I still don't exactly understand the source of the deadlock (my best guess is that get
doesn't really work as expected when called more than once), this seems to work:
from gevent import lock
def queue_identical_calls(f, max_size=100):
pending = {}
@functools.wraps(f)
def wrapped(*args, **kwargs):
key = _make_call_key(args, kwargs)
if key not in pending:
pending[key] = lock.BoundedSemaphore(1)
lock_for_current_call = pending[key]
lock_for_current_call.acquire()
result = f(*args, **kwargs)
lock_for_current_call.release()
if len(pending) > max_size:
pending.clear()
return result
return wrapped