You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线程共享资源:Queue与Dictionary的选择及共享实现

线程间共享变量问题

我有两个包含while循环的线程,线程1处理的数据需由线程2并行处理,需要共享变量。

测试输入:

data = iter([1,2,3,4,5,6,7,8,9])

线程1实现代码:

import threading
from queue import Queue
import time

class Thread1(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)

        self.queue = queue
        _download = {}
        

    def run(self):
        i = 0

        while True:
            _download[i] = next(data)
            self.queue.put(next(data))

            time.sleep(1)
            i += 1

线程2实现代码:

class Thread2(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            self.queue.get()
            
            time.sleep(3)

主函数代码:

q = Queue(maxsize=10)
t = Thread1(q)
s = Thread2(q)
t.start()
s.start()

目前线程2可通过Queue访问共享变量,但我还想让线程2访问线程1中的_download字典。现提出两个问题:

  1. 如何实现线程2对该字典的访问?
  2. 应该选择Queue还是Dictionary来实现线程间的资源共享?

问题1:实现线程2对_download字典的访问

首先要修正线程1的代码:你当前的_download是局部变量,无法被外部访问,需要改成线程1的实例属性(即self._download = {})。之后有两种可行实现方式:

方式1:给线程2传入线程1实例

修改线程2的初始化逻辑,让它持有线程1的引用,直接访问其字典属性:

class Thread2(threading.Thread):
    def __init__(self, queue, thread1):
        threading.Thread.__init__(self)
        self.queue = queue
        self.thread1 = thread1  # 保存线程1实例

    def run(self):
        while True:
            self.queue.get()
            # 直接访问线程1的_download字典
            print(self.thread1._download)
            time.sleep(3)

主函数对应修改:

q = Queue(maxsize=10)
t = Thread1(q)
s = Thread2(q, t)  # 传入线程1实例
t.start()
s.start()

方式2:使用独立的共享字典对象

提前创建字典,初始化线程1和线程2时都传入这个字典实例,让两者共享:

# 提前创建共享字典和线程锁
lock = threading.Lock()
shared_download = {}

class Thread1(threading.Thread):
    def __init__(self, queue, download_dict):
        threading.Thread.__init__(self)
        self.queue = queue
        self.download_dict = download_dict

    def run(self):
        i = 0
        while True:
            try:
                val = next(data)
                # 写字典时加锁保证线程安全
                with lock:
                    self.download_dict[i] = val
                self.queue.put(next(data))
                time.sleep(1)
                i += 1
            except StopIteration:
                break  # 处理迭代器耗尽,避免死循环

class Thread2(threading.Thread):
    def __init__(self, queue, download_dict):
        threading.Thread.__init__(self)
        self.queue = queue
        self.download_dict = download_dict

    def run(self):
        while True:
            try:
                self.queue.get()
                # 读字典时加锁保证线程安全
                with lock:
                    print(self.download_dict)
                time.sleep(3)
                self.queue.task_done()
            except:
                break

主函数对应修改:

q = Queue(maxsize=10)
t = Thread1(q, shared_download)
s = Thread2(q, shared_download)
t.start()
s.start()
t.join()
s.join()

⚠️ 关键提醒:Python普通字典不是线程安全的,多线程同时读写必须加锁,否则会出现数据错乱或程序崩溃。


问题2:选择Queue还是Dictionary实现线程间资源共享

两者适用场景不同,按需选择:

优先用Queue的场景

  • 核心需求是生产者-消费者模式:Queue本身是线程安全的,内置锁机制,无需手动处理锁逻辑,避免bug。
  • 数据单向流动:线程1生产、线程2顺序消费的场景,Queue天然适配,还能通过maxsize限制队列长度,防止内存溢出。
  • 不需要随机访问数据:Queue是先进先出结构,适合按顺序处理数据的场景。

用Dictionary的场景

  • 需要随机访问共享数据:比如线程2要根据键值直接获取特定数据,而非顺序处理。
  • 需要维护共享状态:比如需要保存线程1处理的所有数据状态,但必须配合线程锁使用,保证线程安全。

总结

如果你的核心需求是让线程2并行处理线程1生产的数据,优先选Queue,它更贴合场景且线程安全。如果需要额外访问线程1的状态数据,可以结合共享字典+锁的方式,但务必做好线程安全保护。


内容的提问来源于stack exchange,提问作者bugrahaskan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:16:06