Python 在具有线程锁定的FIFO队列中执行函数
我想在FIFO队列中执行函数调用,并从每次调用中获得结果Python 在具有线程锁定的FIFO队列中执行函数,python,python-multithreading,Python,Python Multithreading,我想在FIFO队列中执行函数调用,并从每次调用中获得结果 def func1(arg1): return arg1 def func2(arg1): return arg1 我将随机从不同线程调用这些函数。因此,基本上我想要的是一次只执行其中一个函数,并且我希望能够从每个调用中获取返回值。尝试以下方法: def func1(arg1): return arg1 def func2(arg1): return arg1 import threading impo
def func1(arg1):
return arg1
def func2(arg1):
return arg1
我将随机从不同线程调用这些函数。因此,基本上我想要的是一次只执行其中一个函数,并且我希望能够从每个调用中获取返回值。尝试以下方法:
def func1(arg1):
return arg1
def func2(arg1):
return arg1
import threading
import time
def func1(arg1):
return arg1
def func2(arg1):
return arg1
def square(x):
time.sleep(5)
return x * x
one_at_a_time = threading.Lock()
action_to_func_mapping = {
"action1": func1,
"action2": func2,
"square_number": square,
}
def dispatch(action, arg1):
one_at_a_time.acquire()
func_to_call = action_to_func_mapping[action]
func_result = func_to_call(arg1)
one_at_a_time.release()
return func_result
下面是一个例子:
if __name__ == '__main__':
square_result = dispatch('square_number', 2)
print(square_result)
func1_result = dispatch('action1', 3)
print(func1_result)
>>> python dispatch.py
4
3
这里看不到锁的效果:示例是单线程的,线程之间永远不会有任何争用。您可以使用一些简单的线程代码来更新问题,以显示锁的作用
在多线程上下文中,上述代码将阻止其他线程,并等待第一个线程完成其函数的执行。在您的应用程序中,您可能可以做一些更有效率的事情。例如,每个函数可能有一个锁,而不是为所有函数调用一次一个漏斗:
action_to_func_mapping = {
"action1": func1,
"action2": func2,
"square_number": square,
}
action_to_func_with_perfunc_lock = {action: (func, threading.Lock())
for action, func in action_to_func_mapping.items()}
def dispatch(action, arg1):
func_to_call, func_lock = action_to_func_with_perfunc_lock[action]
func_lock.acquire()
func_result = func_to_call(arg1)
func_lock.release()
return func_result
>>> python dispatch.py
4
3
这一次,square\u号
将阻止下一个square\u号
,直到第一个操作完成,但是action1
或action2
不会被square\u号
呼叫阻止
这里使用的一些Python工具:,元组解包。这里是一个完整的示例,其中包含FIFO队列和线程,对比了每个函数的锁和一次一个的锁。前面的答案是正确的,但无法演示锁定策略及其效果,因为那里的代码是单线程的。现在的答案引入了线程,因此线程锁定确实发生了,并且您可以看到结果
import threading
from collections import deque
from time import sleep, time
def duck(behaviour):
sleep(1)
return behaviour
def sloth(behaviour):
sleep(5)
return behaviour
def swift(behaviour):
sleep(0.1)
return behaviour
animal_to_func = {
"sloth": sloth,
"duck": duck,
"swift": swift,
}
one_at_a_time_lock = threading.Lock()
animal_to_func_with_per_animal_lock = {action: (func, threading.Lock())
for action, func in animal_to_func.items()}
fifo = deque()
class AnimalThread(threading.Thread):
def __init__(self, thread_id, use_per_animal_lock=False):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.use_per_animal_lock = use_per_animal_lock
def run(self):
while len(fifo):
animal, behaviour = fifo.popleft()
animal_action = dispatch(animal, behaviour, self.use_per_animal_lock)
print(' (thread %s) %s: %s' % (self.thread_id, animal, str(animal_action)))
def dispatch(animal, behaviour, use_per_animal_lock=False):
if use_per_animal_lock:
animal_function, lock = animal_to_func_with_per_animal_lock[animal]
else:
lock = one_at_a_time_lock
animal_function = animal_to_func[animal]
lock.acquire()
what_just_happened = animal_function(behaviour)
lock.release()
return what_just_happened
if __name__ == '__main__':
monday_morning = [
('sloth', 'wake up'),
('sloth', 'blink'),
('sloth', 'go back to sleep'),
('duck', 'wake up'),
('duck', 'quack'),
('duck', 'waddle'),
('duck', 'swim'),
('duck', 'fight duck #2'),
('duck', 'quack'),
('swift', 'wake up'),
('swift', 'catch insects'),
('swift', 'feed chicks'),
]
# essentially unlimited threads to force locks to be used
no_of_threads = len(monday_morning)
print('One at a time, no pushing and shoving!...')
# load the FIFO queue the threads will consume
fifo.extend(monday_morning)
# start threads
threads = [AnimalThread(i) for i in range(no_of_threads)]
[thread.start() for thread in threads]
# wait for threads to finish
[thread.join() for thread in threads]
print('One of each kind of animal at a time...')
# load the FIFO queue the threads will consume
fifo.extend(monday_morning)
# start threads
threads = [AnimalThread(threadno, use_per_animal_lock=True) for threadno in range(no_of_threads)]
[thread.start() for thread in threads]
# wait for threads to finish
[thread.join() for thread in threads]
下面是一个运行示例:
One at a time, no pushing and shoving!...
(thread 0) sloth: wake up
(thread 1) sloth: blink
(thread 2) sloth: go back to sleep
(thread 3) duck: wake up
(thread 4) duck: quack
(thread 5) duck: waddle
(thread 6) duck: swim
(thread 7) duck: fight duck #2
(thread 8) duck: quack
(thread 9) swift: wake up
(thread 10) swift: catch insects
(thread 11) swift: feed chicks
One of each kind of animal at a time...
(thread 9) swift: wake up
(thread 10) swift: catch insects
(thread 11) swift: feed chicks
(thread 3) duck: wake up
(thread 4) duck: quack
(thread 5) duck: waddle
(thread 6) duck: swim
(thread 0) sloth: wake up
(thread 7) duck: fight duck #2
(thread 8) duck: quack
(thread 1) sloth: blink
(thread 2) sloth: go back to sleep
一次一个锁遵循FIFO队列中项目的顺序。它是一个一次只允许调用一个函数的漏斗。它的问题在于,它有效地将多线程应用程序转换为串行单线程应用程序
当上述代码中有每个动物的锁时,动物一次只能做一件事(树懒不能同时醒来和眨眼),但它们彼此独立,可以继续自己的生活。雨燕在鸭子和树懒醒来之前就结束了。但是因为鸭子早上很忙,一次只能做一件事,树懒在鸭子吃完之前就醒了
这种锁定在时间敏感的应用程序中非常有用,在这些应用程序中,特定类型的函数需要按照它们到达队列的顺序进行处理。货币交易就是一个例子,您可能有多个工作单元与一个帐户相关,这些工作单元必须按照它们到达队列的顺序进行处理。那么您的队列在哪里?你的线在哪里?您很难期望我们为您编写所有这些内容。我认为问题涉及多功能分派和线程锁定,而不是队列和线程的实现。可能会更清楚,但这里可能有第二语言问题?@Majides你能把你的问题说清楚吗?我仍然不确定您想要的是单个功能块还是多功能块(如第二个答案中的duck swift sloth示例)。我很乐意帮助您编辑问题您答对了我的问题。我正在尝试在我的应用程序中使用您的代码,看看它是如何工作的。关于第二语言问题,你也是对的:)。谢谢。很高兴我们在同一页@majidse。我已经添加了一个每个函数锁定的例子——不清楚您是想要每个函数锁定,还是想要一个用于所有函数调用的一次一个漏斗。