【问题标题】:How to use multithreading with divide and conquer?如何在分而治之的情况下使用多线程?
【发布时间】:2019-04-14 04:01:24
【问题描述】:

我是 Python 新手,一直在尝试使用多线程。已经有一个关于这个话题的深入的comment on Stackoverflow,但我还有一些问题。

我的程序的目标是创建和填充一个数组(虽然我猜在技术上它必须在 Python 中称为“列表”)并通过“分而治之”算法对其进行排序。不幸的是,许多用户似乎将术语“列表”和“数组”混为一谈,尽管它们并不相同。如果我的评论中使用了“数组”,请记住我发布了来自各种资源的不同代码,并且为了尊重原作者,没有更改其内容。

我用于填充列表 count 的代码非常简单

#!/usr/bin/env python3
count = []
i = 149
while i >= 0:
    count.append(i)
    print(i)
    i -= 1

之后我在“分而治之”的主题上使用this very handy guide 创建了两个用于排序的列表,稍后将它们合并。我现在主要关心的是如何在多线程中正确使用这些列表。

earlier mentioned post 中有人认为,基本上只需要几行代码就可以使用多线程:

from multiprocessing.dummy import Pool as ThreadPool 
pool = ThreadPool(4)

还有

results = pool.starmap(function, zip(list_a, list_b))

传递多个列表。

我尝试修改代码但失败了。我的函数的参数是def merge(count, l, m, r)(用于将列表count分为左右两部分),两个临时创建的列表分别称为LR

def merge(arr, l, m, r): 
    n1 = m - l + 1
    n2 = r- m 

    # create temp arrays 
    L = [0] * (n1) 
    R = [0] * (n2) 

但每次我运行程序时,它都会返回以下错误消息:

Traceback (most recent call last):
  File "./DaCcountdownTEST.py", line 71, in <module>
    results = pool.starmap(merge,zip(L,R))
NameError: name 'L' is not defined

我不知道问题的原因。

非常感谢任何帮助!

【问题讨论】:

  • 听起来好像无论在哪里执行results = pool.starmap(merge,zip(L,R)) 语句,都没有定义L 变量。
  • 我认为您的代码可能存在许多问题。但眼前的问题似乎是LR 是在merge 的范围内定义的,但您却试图在未定义的外部范围内使用它们。
  • 感谢您的帮助。正如你们俩所说,这可能是我错过的范围问题。由于我是 python 新手,我可能无意中弄乱了缩进。那好吧。考虑到“问题的数量”,我不敢苟同。用于填充列表的代码有效,我已经尝试过了,它完成了它应该做的事情。我从 GeeksForGeeks 复制粘贴的其余代码,它也应该可以工作。所以我认为,正如他们所说,这是一个“第 8 层问题”。因此,我将不得不深入研究代码,直到找到问题的根源。
  • 顺便感谢 martineau 的编辑。

标签: python python-3.x multithreading python-multithreading


【解决方案1】:

我不确定您的代码到底出了什么问题,但这里有一个完整的工作示例,它是 the mergeSort code you linked to 的多线程版本:

from multiprocessing.dummy import Pool as ThreadPool 

# Merges two subarrays of arr[]. 
# First subarray is arr[l..m] 
# Second subarray is arr[m+1..r] 
def merge(arr, l, m, r): 
    n1 = m - l + 1
    n2 = r- m 

    # create temp arrays 
    L = [0] * (n1) 
    R = [0] * (n2) 

    # Copy data to temp arrays L[] and R[] 
    for i in range(0 , n1): 
        L[i] = arr[l + i] 

    for j in range(0 , n2): 
        R[j] = arr[m + 1 + j] 

    # Merge the temp arrays back into arr[l..r] 
    i = 0     # Initial index of first subarray 
    j = 0     # Initial index of second subarray 
    k = l     # Initial index of merged subarray 

    while i < n1 and j < n2 : 
        if L[i] <= R[j]: 
            arr[k] = L[i] 
            i += 1
        else: 
            arr[k] = R[j] 
            j += 1
        k += 1

    # Copy the remaining elements of L[], if there 
    # are any 
    while i < n1: 
        arr[k] = L[i] 
        i += 1
        k += 1

    # Copy the remaining elements of R[], if there 
    # are any 
    while j < n2: 
        arr[k] = R[j] 
        j += 1
        k += 1

# l is for left index and r is right index of the 
# sub-array of arr to be sorted 
def mergeSort(arr,l=0,r=None):
    if r is None:
        r = len(arr) - 1

    if l < r: 
        # Same as (l+r)/2, but avoids overflow for 
        # large l and h 
        m = (l+(r-1))//2

        # Sort first and second halves
        pool = ThreadPool(2)
        pool.starmap(mergeSort, zip((arr, arr), (l, m+1), (m, r)))
        pool.close()
        pool.join()

        merge(arr, l, m, r)

下面是对代码的简短测试:

arr = np.random.randint(0,100,10)
print(arr)
mergeSort(arr)
print(arr)

产生以下输出:

[93 56 55 60  0 28 17 77 84  2]
[ 0  2 17 28 55 56 60 77 84 93]

遗憾的是,它似乎确实比单线程版本慢很多。但是,当涉及到 Python 中的多线程计算绑定任务时,这种减速是 parcourse

【讨论】:

  • 感谢您的回答。这正是我使用的代码。我复制粘贴它,看看它是否符合我的要求。但我得到了一个错误代码。我很确定这一定是我的错,可能是我错过的东西,最终是用户 tel 建议的范围问题。考虑到它很慢,我想那将是 GIL。稍后我将不得不处理这个问题,但目前我主要对启动和运行它感兴趣。
  • 我再次复制并粘贴了代码,它可以工作了。所以真的是我笨手笨脚。我可能应该早点睡觉。再次感谢您的帮助 - 现在我将拥有我想要(和需要)的所有时间来处理那个讨厌的小 GIL。
猜你喜欢
  • 2014-10-20
  • 2020-05-31
  • 1970-01-01
  • 2013-11-09
  • 2013-02-05
  • 1970-01-01
  • 2014-11-10
  • 2013-01-31
  • 1970-01-01
相关资源
最近更新 更多