Python gevent/线程导致一些死锁
我有这段代码,其目的是消除重复请求Python gevent/线程导致一些死锁,python,multithreading,deadlock,gevent,Python,Multithreading,Deadlock,Gevent,我有这段代码,其目的是消除重复请求 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)
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
我怀疑这是某种原因造成了僵局(这种情况偶尔发生一次,我无法重现)
使用线程和gevent时都会发生这种情况
是否允许反复使用get
当不涉及线程时,这段代码甚至会产生死锁吗
请注意,它在其他gevent任务下运行,因此衍生任务可能会衍生其他任务,以防出现问题。您的问题是代码不异步。您需要让函数本身处理密钥更新,然后在while循环中测试您的值。这是异步工作的一个例子。您可以通过注意最后一个元素有时在列表中首先出现来证明这一点
import gevent
import random
pending = {}
def dedup_requests(key, *args, **kwargs):
global pending
if key not in pending:
gevent.spawn(ftest, key, *args, **kwargs)
def ftest(key, *args, **kwargs):
global pending
z = random.randint(1,7)
gevent.sleep(z)
pending[key] = z
return z
l = ['test','test2','test3']
for i in l:
dedup_requests(i)
while 1:
if set(pending.keys()) != set(l):
print(pending)
else:
print(pending)
break
gevent.sleep(1)
虽然我仍然不完全理解死锁的来源(我最好的猜测是,
get
在多次调用时并没有像预期的那样工作),但这似乎是可行的:
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
谢谢,但这似乎不能解决同样的问题。关键是阻止多个“线程”同时请求的相同工作(想象一下,在同一秒内多次使用同一字符串调用)。在您的解决方案中,睡眠(我假设是模拟网络)会发生很多次。您的解决方案本质上是记忆。set函数为您消除重复。睡眠允许应用程序在绿叶中移动,
Sleep(0)
将允许您实时移动。IIUCset
没有足够早地消除重复,也没有使用字典。为了更好地理解我的意思,在f\u test
中添加一行表示网络请求的代码(例如remote\u procedure\u call()
),通过遵循代码,您将看到这一行将被l
中的每个元素调用,而不考虑重复。我刚才提供了异步的示例。在ftest中,您将在运行函数之前检查该键,如果该键存在,您将取消。我认为您下面的答案破坏了异步进程,并将其转换回单线程阻塞进程。