[Python3] 线程安全的数据共享容器 List,Set,Dict

多个线程可以共享一个列表 (list),但要注意并发访问时可能引发的问题

线程安全的List

  • 以下实现了一个行为类似list的类, 并且在多线程环境下安全
  • 这个类提供了与 list 类似的功能,同时确保了线程安全。这对于在多线程环境中使用列表而又避免数据竞争非常有用。
import threading

class ThreadSafeList:
    def __init__(self):
        self._list = []
        self._lock = threading.Lock()

    def append(self, item):
        with self._lock:
            self._list.append(item)

    def extend(self, items):
        with self._lock:
            self._list.extend(items)

    def insert(self, index, item):
        with self._lock:
            self._list.insert(index, item)

    def remove(self, item):
        with self._lock:
            self._list.remove(item)

    def pop(self, index=-1):
        with self._lock:
            return self._list.pop(index)

    def clear(self):
        with self._lock:
            self._list.clear()

    def index(self, item):
        with self._lock:
            return self._list.index(item)

    def count(self, item):
        with self._lock:
            return self._list.count(item)

    def sort(self, *, key=None, reverse=False):
        with self._lock:
            self._list.sort(key=key, reverse=reverse)

    def reverse(self):
        with self._lock:
            self._list.reverse()

    def __getitem__(self, index):
        with self._lock:
            if isinstance(index, slice):
                return self._list[index.start:index.stop:index.step]
            else:
                return self._list[index]

    def __setitem__(self, index, value):
        with self._lock:
            self._list[index] = value

    def __delitem__(self, index):
        with self._lock:
            del self._list[index]

    def __len__(self):
        with self._lock:
            return len(self._list)

    def __iter__(self):
        with self._lock:
            return iter(self._list.copy())

在这个 ThreadSafeList 类中:

  • 我们用 threading.Lock 来确保线程安全。
  • 大多数 list 方法都得到了实现,包括 appendextendinsertremovepopclearindexcountsortreverse 等。
  • __getitem____setitem__ 等方法也被实现,以支持索引和切片操作。
  • __iter__ 返回列表的副本,以防止迭代时出现竞争。

__iter__ 方法中,返回列表的副本是为了确保迭代过程中不受其他线程影响,因此使用浅拷贝(shallow copy)就足够了。

  • 浅拷贝会创建一个新的对象,该对象的内容与原始对象相同,但是内部元素的引用仍然指向原始对象中的元素。因此,如果对这些元素进行修改,原始对象和副本都会受到影响。
  • 但是在这种情况下,因为我们已经在__iter__方法中使用了锁来确保线程安全,所以在迭代过程中不会出现同时修改的情况,因此返回列表的浅拷贝就足够了。
  • 如果返回的是深拷贝(deep copy),则会完全复制原始列表及其内部元素,这可能会带来额外的开销,并且在这个情况下并不是必要的。

线程安全的Set

Python 的内置 set 对象本身并不是线程安全的。虽然个别操作(如添加和删除单个元素)可能在底层是原子性的,但多个线程同时操作 set 时可能会导致数据竞争或不一致的结果。因此,在多线程环境中同时操作 set 时,需要额外的同步机制来确保线程安全。

常见的实现方式包括:

  • 锁(Lock):使用 threading.Lock 来保护 set,确保在操作 set 时没有其他线程干扰。例如,将 set 的所有访问都包裹在 with 语句中使用锁。
  • 线程安全的集合:自己编写一个线程安全的集合类,类似于我之前示范的 ThreadSafeList。这个类将 set 的所有操作用锁来保护。

示例代码:

import threading

class ThreadSafeSet:
    def __init__(self):
        self._set = set()
        self._lock = threading.Lock()

    def add(self, item):
        with self._lock:
            self._set.add(item)

    def remove(self, item):
        with self._lock:
            self._set.remove(item)

    def discard(self, item):
        with self._lock:
            self._set.discard(item)

    def __contains__(self, item):
        with self._lock:
            return item in self._set

    def __iter__(self):
        with self._lock:
            return iter(self._set.copy())

在这个示例中,ThreadSafeSet 类使用 threading.Lock 来确保所有操作是线程安全的。我们使用浅拷贝来获取 set 的副本,以防止迭代期间的竞争。

总之,如果您在多线程环境中需要使用 set,建议使用锁或类似的同步机制来确保线程安全。

线程安全的 Dict

在 Python 3 中,原生的 dict 类型本身不是线程安全的。

虽然在读操作时通常不会出现问题,但在写操作(包括更新、删除和插入)时,多个线程同时操作一个 dict 对象可能导致数据不一致或引发竞争条件。

因此,建议在多线程环境中对 dict 对象的访问进行同步控制。

class ThreadSafeDict:
    def __init__(self):
        self._lock = threading.Lock()
        self._dict = {}

    def set(self, key, value):
        with self._lock:
            self._dict[key] = value

    def get(self, key, default=None):
        with self._lock:
            return self._dict.get(key, default)

    def delete(self, key):
        with self._lock:
            if key in self._dict:
                del self._dict[key]

    def keys(self):
        with self._lock:
            return list(self._dict.keys())

    def values(self):
        with self._lock:
            return list(self._dict.values())

    def items(self):
        with self._lock:
            return list(self._dict.items())

    def update(self, other):
        with self._lock:
            self._dict.update(other)

    def clear(self):
        with self._lock:
            self._dict.clear()

    def __getitem__(self, key):
        with self._lock:
            return self._dict[key]

    def __setitem__(self, key, value):
        with self._lock:
            self._dict[key] = value

    def __delitem__(self, key):
        with self._lock:
            del self._dict[key]

    def __contains__(self, key):
        with self._lock:
            return key in self._dict
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值