如何防止并发期货库循环遍历以前迭代的项目?

How to prevent concurrent futures library from looping over previously iterated items?

我有一个数字 ID 列表 (lst1)(大约 30 万个 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)

整数是不可变的。所以你可以使用

使你的计数器全局化
global counter

您还可以使用 itertools.count

定义全局 counter 对象(非整数)

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

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

现在:

counter = counter+ 1

变为:

counter = next(counter_object)

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

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

另一个问题是 get_data 不应该 return 一个列表,而是一个项目。让 executor.map 创建列表(你的循环是 useless/harmful 因为它乘以计算次数)

所以总结一下:

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 被迭代。要创建列表,您必须对其进行 force 迭代:

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