首页 > 解决方案 > 如何防止并发期货库循环先前迭代的项目?

问题描述

我有一个lst1数字 ID(大约 300K ID)的列表(),我将其传递给 API,并将 api 结果附加到另一个列表(lst)中,如下所示:

lst = []
lst1 = [1,2,3,4,5,6]

print(len(lst1))
counter = 0
for i in lst1:
    url = 'url.com/Id={}'.format(i)
    while True:
        try:
            xml_data1 = requests.get(url).text
            counter = counter+ 1
            print(counter)
            #print(xml_data1)
            break
        except requests.exceptions.RequestException as e:
            print(e)
    lst.append(xml_data1)

当我应用 future.concurrent 库时,代码会不断循环相同的 ID。我可以告诉这一点,因为柜台号码不断重复,我该如何防止这种情况?

我如何应用 futures.concurrent 库的代码:

def get_data(xml):
    print(len(lst1))
    #counter = 0
    for i in lst1:
        url = 'url.com/Id={}'.format(i)
        while True:
            try:
                xml_data1 = requests.get(url).text
                counter = counter+ 1
                print(counter)
                #print(xml_data1)
                break
            except requests.exceptions.RequestException as e:
                print(e)
        lst.append(xml_data1)

with futures.ThreadPoolExecutor() as executor:  
    df_list = executor.map(get_data, lst1)

编辑:

def get_data(xml):
    #counter = 0
    for i in lst1:
        url = 'url.com/Id={}'.format(i)
        while True:
            try:
                xml_data1 = requests.get(url).text
                counter = next(counter_object)
                print(counter)
                #print(xml_data1)
                break
            except requests.exceptions.RequestException as e:
                print(e)
        lst.append(xml_data1)
    return lst
with futures.ThreadPoolExecutor() as executor:  
    lst = executor.map(get_data, lst1)

标签: pythonpython-3.xconcurrent.futures

解决方案


整数是不可变的。所以你可以让你的计数器全局使用

global counter

您还可以使用定义一个全局counter对象(不是整数)itertools.count

这是我的首选方法,因为它避免了global在像整数这样的不可变对象上使用,这总是会导致错误和误解。

import itertools
counter_object = itertools.count()  # default: starts at 0

现在:

counter = counter+ 1

变成:

counter = next(counter_object)

并且工作线程之间的值不会相同。

这依赖于 CPython 具有使操作安全的全局解释器锁这一事实。如果您不使用 CPython,则必须使用线程锁定机制来保护对象免受并发修改。

另一个问题是不get_data应该返回一个列表而是一个项目。让我们executor.map创建列表(并且您的循环是无用/有害的,因为它会乘以计算次数)

所以总结一下:

def get_data(xml):
    url = 'url.com/Id={}'.format(xml)
    while True:
        try:
            xml_data1 = requests.get(url).text
            counter = next(counter_object)
            print(counter)
            break
        except requests.exceptions.RequestException as e:
            print(e)
    return xml_data1

最后,executor.map被迭代。要创建一个列表,您必须对其强制迭代:

with futures.ThreadPoolExecutor() as executor:  
    df_list = list(executor.map(get_data, lst1))

推荐阅读