python - 在 Python 中使用多线程迭代字典

标签 python multithreading dictionary

我想在Python中使用多线程和队列(以限制线程数)来迭代字典中的字典(模拟目录或网站的结构)。我创建了 mainDict 来模拟这个

mainDict = {"Layer1": {"Layer11": 1, "Layer12": 1, "Layer13": 1, "Layer14": 1, "Layer15": 1," Layer16": 1},
        "Layer2": {"Layer21": 2, "Layer22": 2, "Layer23": 2, "Layer24": 2, "Layer25": 2, "Layer26": 2},
        "Layer3": {"Layer31": 4, "Layer32": 4, "Layer33": 4, "Layer34": 4, "Layer35": 4, "Layer36": 4},
        "Layer4": {"Layer41": 8, "Layer42": 8, "Layer43": 8, "Layer44": 8, "Layer45": 8, "Layer46": 8},
        "Layer5": {"Layer51": 16, "Layer52": 16, "Layer53": 16, "Layer54": 16, "Layer55": 16, "Layer56": 16},
        "Layer6": {"Layer61": 32, "Layer62": 32, "Layer63": 32, "Layer64": 32, "Layer65": 32, "Layer66": 32}}

还有一个 Crawler 类,用于为 mainDict 的每个第一个子词典实例化一个爬虫。

我的想法是,我想创建 2 个可以爬行到 Layer(i) (i=1..6) 的线程(一次创建有限数量的线程/爬虫,以减少 CPU 使用率)。每个线程都会爬行,直到到达“树”的叶子,然后移动到下一个字典(例如,爬虫 0 将经过 Layer1,爬虫 1 将经过 Layer2,完成后将经过 Layer3...)。

class Crawler:
def __init__(self, rootDict, number_of_delay, crawler):
    self.crawler = crawler
    self.rootDict = rootDict
    self.number_of_delay = number_of_delay

def crawlAllLeaves(self, myDict):
    for k, v in myDict.items():
        if isinstance(v, dict):
            print("Crawler {} is crawling {}".format(self.crawler, k))
            self.crawlAllLeaves(v)
        else:
            print("Crawler {} reached the value {} for key {}".format(self.crawler, v, k))
            time.sleep(self.number_of_delay + v)

def someAuxFunc():
    #to simulate some loading time
    time.sleep(2)

def createWorker(q, delayNumber, crawler):
    tc = Crawler(mainDict[q.get()], delayNumber, crawler)
    tc.crawlAllLeaves(tc.rootDict)

def threader(q, delayNumber, crawler):
    while True:
        print("crawler {}: has gotten the url {}".format(crawler, q.get())) 
        createWorker(q, delayNumber, crawler)
        print("crawler {}: has finished the url {}".format(crawler, q.get())) 
        q.task_done()

q = Queue()
number_of_threads = 2
delayNumber = 2

for thread in range(number_of_threads):
    th = threading.Thread(target=threader, args=(q, delayNumber, thread,))
    th.setDaemon(True)
    th.start()


for key, value in mainDict.items():
    someAuxFunc()
    print("QUEING {}".format(key))
    q.put(key)

q.join()

我有两个问题:

  1. 它只创建 2 个线程并获取队列的前 2 个元素(子词典),然后它不执行任何操作,甚至退出;它保持悬挂状态
  2. 在 threader() 函数中,它表示它将获得一个子词典,但会迭代另一个不同的词典,如crawlAllLeaves() 中的 print 所示

你能帮我解决这个问题吗,因为我想学习 Python 和线程,但我不知道我做错了什么?

最佳答案

您的问题在于队列的处理,它解释了您的两个问题。您继续从队列中读取数据,而不是使用从队列中实际收到的值。看看这个(固定的)代码:

def createWorker(bar, delayNumber, crawler):
    tc = Crawler(mainDict[bar], delayNumber, crawler)
    tc.crawlAllLeaves(tc.rootDict)

def threader(q, delayNumber, crawler):
    while True:
        foo = q.get()
        print("crawler {}: has gotten the url {}".format(crawler, foo)) 
        createWorker(foo, delayNumber, crawler)
        print("crawler {}: has finished the url {}".format(crawler, foo)) 
        q.task_done()

在您的 threader 中我们现在将队列读取一次到一个变量,然后将该变量传递给 createWorker 。在你的createWorker您使用这个值而不是获取另一个值。

您的原始代码最初在第一个打印语句中从队列中获取一个值。它打印该值然后丢弃。然后你调用createWorker ,您可以从队列中接收下一个值并开始处理该值。最后,第二个打印语句从队列中获取另一个值并打印它。 print 语句中显示的值实际上都没有传递给 createWorker

Queue.get()如果那里没有任何东西,则默认阻止。当您为每个处理的值获取三个值时,您的结果是无论是什么,但绝对不是您想要的结果。你的代码块在最后 q.join() 中正如您所使用的 get()三次从队列中获取值但使用 task_done只有一次。因此,您的连接会阻塞,因为它假设仍有任务正在进行中。

关于python - 在 Python 中使用多线程迭代字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46711169/

相关文章:

python - 替换Python 3中的文本但它只读取一行

java 当我调用 Thread.sleep() 时,数据的可见性

objective-c - 保存时核心数据和多线程崩溃

python - 在 Python 中将值附加到字典

java - 如何实现具有2个独立键的 map ?

Python 字典详细信息

python - 属性错误 : 'Settings' object has no attribute 'OSCAR_REQUIRED_ADDRESS_FIELDS'

python - 是否有适用于 Python 的标准词法分析器/解析器工具?

Python 在除法时保持精度

c# - 线程间通信不杀线程