Python ThreadPoolExecutor以迭代方式运行,而不是与线程一起运行

Python ThreadPoolExecutor以迭代方式运行,而不是与线程一起运行,python,multithreading,Python,Multithreading,我有以下代码: def getdata(page, hed, limit): data = [] print page datarALL = [] url = 'http://...WithTotal=true&cultureid=1&offset={0}&limit={1}'.format(value_offset, value_limit) print page print url responsedata =

我有以下代码:

def getdata(page, hed, limit):
    data = []
    print page
    datarALL = []
    url = 'http://...WithTotal=true&cultureid=1&offset={0}&limit={1}'.format(value_offset, value_limit)
    print page
    print url
    responsedata = requests.get(url, data=data, headers=hed, verify=False)
    if responsedata.status_code == 200:  # 200 for successful call
        responsedata = responsedata.text
        jsondata = json.loads(responsedata)
        if "results" in jsondata:
            if jsondata["results"]:
                datarALL = datarALL + jsondata["results"]
    print "page {} finished".format(page)
    return data


def start(data, auth_token):
    # # ---  Get data from API --
    hed = {'Authorization': 'Bearer ' + auth_token, 'Accept': 'application/json'}

    urlApi = 'http://...WithTotal=true&cultureid=1&offset=0&limit=1'
    responsedata = requests.get(urlApi, data=data, headers=hed, verify=False)
    num_of_records = int(math.ceil(responsedata.json()['total']))
    value_limit = 249  # Number of records per page.
    num_of_pages = num_of_records / value_limit
    print num_of_records
    print num_of_pages
    pages = [i for i in range(0, num_of_pages - 1)]
    from concurrent.futures import ThreadPoolExecutor, as_completed
    datarALL = []
    with ThreadPoolExecutor(max_workers=num_of_pages) as executor:
        futh = [executor.submit(getdata(page, hed, value_limit), page) for page in pages]
        for data in as_completed(futh):
            datarALL = datarALL + data.result()
    return datarALL
基本上开始创建页面,并在每个页面上运行getdata。 这张照片告诉我:

0
http://...WithTotal=true&cultureid=1&&offset=0&limit=249
page 0 finished
1
http:/...WithTotal=true&cultureid=1&&offset=249&limit=249
page 1 finished
etc...
然而,我希望所有页面都会在同一时间创建,然后当线程获得CPU时间时,每个页面都会运行,但实际情况是,只有当getdata完成时,才会创建下一个页面。这意味着线程在这里是无用的。我应该注意到,每个getdata调用大约需要4-5分钟才能完成

我怀疑问题就在这里:

futh = [executor.submit(getdata(page, hed, value_limit), page) for page in pages]
它等待getdata完成,然后再运行下一个循环


如何修复它并使其与线程一起工作?

问题是您根本没有在执行器中执行任务。而是调用5分钟函数,然后尝试将其结果作为任务执行:

[executor.submit(getdata(page, hed, value_limit), page) for page in pages]
getdatapage,hed,value_limit是一个函数调用:它调用getdata并等待其返回值

您需要做的是将函数本身传递给submit,如下所示:

executor.submit(getdata, page, hed, value_limit)
我不确定你想用额外的页面做什么,但是如果你想要一个未来的页面元组列表,那就是:

[(executor.submit(getdata, page, hed, value_limit), page) for page in pages]

你必须提交一个函数而不实际调用它!到因此,在您的特定情况下,应该修复getdata函数中的hed和value_limit参数,使其成为具有单个参数页的函数

最简单的解决方案可能如下所示:

getdata_partial = lambda page: getdata(page, hed, value_limit)
然后您可以使用它,如下所示:

futh = [executor.submit(getdata_partial, page) for page in pages]

另一个可能的解决方案是使用。您可能会发现它更加优雅,但想法仍然是一样的。

是不是4-5分钟大部分时间都是CPU占用,运行大量计算?如果是这样,在CPython中,全局解释器Lock GIL意味着一次只能执行其中一个。线程是伟大的,当你有IO限制的计算,如等待网络服务器,但不是很有帮助的CPU限制的工作。但如果这是问题所在,通常可以通过将ThreadPoolExecutor更改为ProcessPoolExecutor来解决。只要它们不需要任何共享数据,并且参数和返回值是可拾取的类型,并且不是太大,它就可以工作。@abarnert函数进行API调用,没有havey计算。。它主要是等待获取记录。需要花费所有时间的操作是:requests.geturi、data=data、headers=hed、verify=False。线程之间没有共享数据。。每个线程都会带来另一块249,然后我将它们合并在一起。@abarnert请参见编辑。。我添加了完整的函数代码,这里不需要使用lambda;execute.submit接受函数、*args和**kwargs。你已经利用了这一点,把页面作为一个论据来传递,所以没有理由对其他论据有任何不同的对待。另外,我知道人们总是滥用这个术语,但是如果你要使用新手不懂的技术术语,你真的应该小心把它们弄对。curry函数和部分应用的函数不是一回事。curried函数是一次接受一个参数并返回一个新函数的函数。如果你真的有一个curried getdata函数,你可以把它叫做getdata\u curriedpagehedvalue\u limit。完全同意,谢谢你的评论!将getdata_curried更改为getdata_partial:关于lambda的使用,明确表明在当前上下文中,只有页面参数才是真正重要的,并允许我们区分提交的任务。我不确定我是否遵循。这是我第一次尝试多线程。这段代码基于我看到的示例。。我通过页面参数只是为了打印。实际上并不需要。[executor.submitgetdata,page,hed,value_limit,pages-for-page-in-pages]工作得很好!我愿意接受您提出的任何进一步建议。@Programmer120如果您想将函数传递给某人,无论是作为ThreadPoolExecutor的任务,还是作为tkinter.Button的回调,或是任何必须传递函数的内容,都不要调用函数并传递结果,这与多线程无关。