我使用Python 2.7,我有一个任务来编写一个使用多个线程计算阶乘的函数。我尝试使用传统的递归方法来做到这一点,比如
def factorial(n):
if n < 1:
return 1
else:
return n * factorial(n - 1)
但似乎这种方式并不适用于多线程。有没有办法使用多个线程计算阶乘?
答案 0 :(得分:4)
在多线程应用程序中,最好尽量减少不同线程之间存在的数据依赖关系。
在你提到的阶乘的递归解决方案中,很难找到不依赖于其他计算结果的计算。
一种独特的方法是将阶乘分为多个部分。 例如,对于两个线程,可以执行以下操作:
n! = [1 * 2 * 3 * .. * (n/2)] * [(n/2 + 1) * ... * n]
第一个线程将计算值:
v1 = 1 * 2 * 3 * .. * (n/2)
第二个线程将计算:
v2 = (n/2 + 1) * ... * n
然后,当两个线程都完成后,主线程将计算n! = v1 * v2
。
通过将输入因子分成k
个不同的部分而不是仅仅两个,可以推广使用k
个线程,如上例所示。
答案 1 :(得分:1)
我非常喜欢the idea presented in the other answer。
当阶乘为数字[1,n]的computed as the product时:
numbers = range(1,n+1)
您可以使用切片生成工人要处理的数字。例如:
slices = [numbers[i::nworkers] for i in range(nworkers)]
# using n = 10 and nworkers = 3, this produces:
# [[1, 4, 7, 10], [2, 5, 8], [3, 6, 9]]
Map这是process pool,然后减少这些产品的结果以获得最终解决方案。
请勿使用threading模块来实现此功能。这是一个CPU绑定任务,将被Global Interpreter Lock阻止。 multiprocessing模块使用进程而不是线程来支持这一步。
答案 2 :(得分:0)
阶乘只是一系列数字的乘法。由于乘法为associative,因此您可以按任意顺序乘以数字。更具体地说,您可以按照自己喜欢的方式将序列分成任意数量的部分,将部分相乘,然后合并结果。
由于CPython的GIL,你可能最终一次只运行一个线程,但任务的本质可能只是简单地练习线程同步。
threading.Thread
和queue.Queue
看起来像是工作的正确工具。我将举两个可能的实现示例:
Queue
和一些Thread
对象,每个对象都可以
另一个更有趣的实现是:
Queue
创建一些线程,每个线程都
Queue
中取一个数字(即不会阻止)这里有趣的部分是队列为空后如何继续:
Queue
并退出,留给主线程在所有线程退出后进行最后的乘法相反,线程可能会将结果推回队列并退出。但是,你需要以某种方式确保在获得最终结果之前并没有所有线程都退出(并推入队列中)。
执行此操作的一种方法是在互锁计数器中跟踪已将多少部分结果推送到队列,并防止线程在检测到要处理最后一个线程时退出:
#at initialization
partial_results_lock = threading.Lock()
partial_results_left=<number of threads>
# in the thread, if the queue is empty
with partial_results_lock:
queue.push(state)
state=1
partial_results_left-=1
if partial_result_left!=0: return # after we start over and push
#the final result, the counter will become -1
<start over>