Python 3.9:使用退避和线程时,全局变量假设“不可能”的值

问题描述 投票:0回答:1

这里我们遇到了一个有趣的情况,这种情况不应该发生,并且似乎是由退避引起的。在退避文档中找不到相关信息,也找不到相关问题。

此代码在带有 Nginx 和 Gunicorn(启用 9 个工作线程)的 Ubuntu 服务器中使用 Python 3.9 运行:

# this runs in Ubuntu server with Nginx and gunicorn (9 workers enabled) with Python 3.9


import backoff  # backoff version 2.2.1
from multiprocessing.dummy import Pool as ThreadPool

tries = 0
MAX_RETRIES = 5


@backoff.on_exception(backoff.constant, ValueError, interval=0.5, max_tries=MAX_RETRIES)
def do_stuff_with_backoff_retry(var_1):
    global tries
    tries = tries + 1
    try:
        # do stuff with var_1 that may generate exception and return something if successfully done
        something = var_1
        return something
    except:
        msg = f'Error at do_stuff_with_backoff_retry function'
        print(msg)
        raise ValueError(msg)


def controller_func(var_1):
    global tries
    tries = 0
    try:
        result = do_stuff_with_backoff_retry(var_1)
        msg = f'[Try {tries} of {MAX_RETRIES}] success at do_stuff_with_backoff_retry function'
        print(msg)
        return result
    except:
        print(f'Failed at do_stuff_with_backoff_retry function')




def do_with_threading():
    list_of_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    pool = ThreadPool(15)
    results2 = pool.map(controller_func, list_of_data)
    pool.close()
    pool.join()
    print(f'results2: {results2}')

如果在极少数情况下以

controller_func(5)
(使用
var_1 = 5
或任何其他值)开始处理,我会收到以下成功消息:

[Try 6 of 5] success at do_stuff_with_backoff_retry function

它不应该得到

Try 6 of 5
,因为 5 是允许的最大尝试次数。

在更罕见的情况下,我会得到

Try 7 of 5

如果处理是从

do_with_threading()
开始的,在常见情况下我会收到类似以下内容的消息:

[Try 11 of 5] success at do_stuff_with_backoff_retry function

[Try 15 of 5] success at do_stuff_with_backoff_retry function

[Try 13 of 5] success at do_stuff_with_backoff_retry function

查看其他记录的数据似乎后台正在重试尊重

MAX_RETRIES = 5
,但似乎
tries = 0
处的
controller_func(var_1)
无法正常工作。

还是我做错了什么?

python multithreading global-variables
1个回答
0
投票

我为克服这种情况制定的解决方案是使用 Redis。

在controller_func处将值

0
(零)设置为Redis中的键,然后,在do_stuff_with_backoff_retry开始时读取键,将其转换为整数,该值增加
1
并再次保存到Redis中。

键名有一个与正在处理的文件关联的可变部分,对于每个线程来说都是唯一的,确保永远不会发生键名冲突。

例如:

文件到进程:

dsjfsdo8wejroscmeiuwerl.txt

key_name = f'Counter_at_redis_for__{file_to_process}'

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.