【问题标题】:Sync a class variable with multiple threads将一个类变量与多个线程同步
【发布时间】:2019-11-21 11:04:00
【问题描述】:

我正在尝试创建一个装饰器,它将全局验证请求存储桶是否已满。 桶大小为 40,泄漏率为每秒 2 个。 我希望能够在保持 bucker sub 40 的同时处理不同请求的多个实例。 self.bucket_current 怎么可能变为负数?另外,如何调试这些线程以及它们的作用?

from time import sleep
from concurrent.futures import ThreadPoolExecutor
from math import ceil

class Counter:
    def __init__(self):
        self.bucket_size = 40
        self.bucket_current = 0
        self.bucket_leak_rate = 2


    def countdown(self, secs):
        self.bucket_current += secs
        print(self.bucket_current)
        r = ceil(self.bucket_current/self.bucket_leak_rate)
        sleep(1)
        while self.bucket_current > 0:
            for _ in range(1, r+1):
                if self.bucket_current != 1:
                    self.bucket_current -= 2
                else:
                    self.bucket_current -= 1

                print(self.bucket_current)
                sleep(1)


c = Counter()

with ThreadPoolExecutor() as executor:
    executor.submit(c.countdown, 9)
    sleep(3)
    executor.submit(c.countdown, 7)

输出:

9
7
5
3
10
8
6
4
2
0
-2
-4
-6
-8
-10
-12
-14

【问题讨论】:

  • 你的预期输出是什么?

标签: python multithreading synchronization python-decorators class-variables


【解决方案1】:

self.bucket_current 怎么可能变成负数?

答案是,根据您的代码,在您的第一行 executor.submit(c.countdown, 9) 之后,线程单独执行,3 秒后 (sleep(3)) 另一个线程加入执行 executor.submit(c.countdown, 7) 并且没有这两个线程之间的任何同步。

你需要提供一种机制来同步这两个线程,这是我有时使用的一个简单的装饰器:

from time import sleep
from concurrent.futures import ThreadPoolExecutor
from math import ceil
from functools import wraps
from threading import Lock


def synchronized(tlockname):
    """A decorator to place an instance based lock around a method """

    def _synched(func):
        @wraps(func)
        def _synchronizer(self, *args, **kwargs):
            tlock = self.__getattribute__(tlockname)
            tlock.acquire()
            try:
                return func(self, *args, **kwargs)
            finally:
                tlock.release()

        return _synchronizer

    return _synched


class Counter:
    def __init__(self):
        self.bucket_size = 40
        self.bucket_current = 0
        self.bucket_leak_rate = 2
        self.bucket_lock = Lock()

    @synchronized("bucket_lock")
    def countdown(self, secs):
        self.bucket_current += secs
        print(self.bucket_current)
        r = ceil(self.bucket_current / self.bucket_leak_rate)
        sleep(1)
        while self.bucket_current > 0:
            for _ in range(1, r + 1):
                if self.bucket_current != 1:
                    self.bucket_current -= 2
                else:
                    self.bucket_current -= 1

                print(self.bucket_current)
                sleep(1)


c = Counter()

with ThreadPoolExecutor() as executor:
    executor.submit(c.countdown, 9)
    sleep(3)
    executor.submit(c.countdown, 7)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多