【问题标题】:How to prevent concurrent futures library from looping over previously iterated items?如何防止并发期货库循环先前迭代的项目?
【发布时间】:2018-11-05 14:17:35
【问题描述】:

我有一个数字 ID 列表 (lst1),我将其传递给 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)

【问题讨论】:

    标签: python python-3.x concurrent.futures


    【解决方案1】:

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

    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 不应该返回一个列表而是一个项目。让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))
    

    【讨论】:

    • 所以这肯定解决了计数器问题,但我将其设置为 df_list 的最后一行不起作用。当我将df_list 更改为lst 时,concurrent.futures 库会在正确的记录数处停止,否则它会继续运行。在任何一种情况下,都不会将任何内容附加到 lst 中。你知道是什么原因造成的吗?
    • 哦,你的get_data函数应该返回一些东西:lst.append(xml_data1)应该被return xml_data1替换:没有副作用,让execute运行。告诉我它是否有效,我忽略了试图解决计数器问题的那部分
    • 如果我删除lst.append(xml_data1) 并替换为return xml_data1,即使我将df_list 设置为lst,也不会在任何地方附加任何内容。我应该如何处理追加?
    • xml_data1 是我想要的结果。但是我应该如何处理追加到列表中?
    • 我进行了编辑,完全符合我的代码。如果我没有将最后一行设置为lst,则进程将继续运行,无论没有附加任何内容
    猜你喜欢
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 2012-09-10
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    相关资源
    最近更新 更多