【问题标题】:Why does my multiprocess Python script never end?为什么我的多进程 Python 脚本永远不会结束?
【发布时间】:2023-04-06 01:58:01
【问题描述】:

我尝试了一些多进程示例,主要是:http://toastdriven.com/blog/2008/nov/11/brief-introduction-multiprocessing/ 我采用了“简单应用程序”,它使用多进程来测试 URL。 当我使用它(在 Python 3.3 中,在 Windows 中的 PyCharm IDE 中)进行一些修改时,有很多 URL,我的脚本永远不会停止,我不明白为什么。

import httplib2
import sys
from multiprocessing import Lock, Process, Queue, current_process

def worker(work_queue, done_queue):
    for url in iter(work_queue.get, 'STOP'):
        try:
            print("In : %s - %s." % (current_process().name, url))
            status_code = print_site_status(url)
            done_queue.put("%s - %s got %s." % (current_process().name, url, status_code))
        except:
            done_queue.put("%s failed on %s with: %s" % (current_process().name, url, str(sys.exc_info()[0])))
    print("Out : %s " % (current_process().name))
    return True

def print_site_status(url):
    http = httplib2.Http(timeout=10)
    headers, content = http.request(url)
    return headers.get('status', 'no response')

def main():
    workers = 8
    work_queue = Queue()
    done_queue = Queue()
    processes = []
    with open("Annu.txt") as f: # file with URLs
        lines = f.read().splitlines()
    for surl in lines:
        work_queue.put(surl)

    for w in range(workers):
        p = Process(target=worker, args=(work_queue, done_queue))
        p.start()
        processes.append(p)
        work_queue.put('STOP')

    for p in processes:
        p.join()
    print("END")
    done_queue.put('STOP')

    for status in iter(done_queue.get, 'STOP'):
        print(status)

if __name__ == '__main__':
    main()

我清楚地看到了所有已测试的 URL 状态,以及表明进程结束的所有进程“Out”消息,但从来没有看到我的“END”消息。 我使用的 URL 列表是:http://www.pastebin.ca/2946850

那么...我的错误在哪里?是否与:Python multiprocessing threads never join when given large amounts of work 重复?

一些信息:当我在代码中的任何地方禁止“done_queue”时:它是有效的。

【问题讨论】:

  • 注意END不会像你想的那样打印在END。向上滚动接近一半,您会在那里看到它。
  • @dopstar 抱歉,您的评论不清楚,您是否说“END”消息不在脚本末尾?如果是:我知道,'END' 在这里表示进程已结束。
  • 在打印完 END 后,您还打印了完成队列中的状态,因此这会将 END 大致放在中间。您有 500 多个网址,因此您将有 1k 多个打印输出,中间某处有 END。
  • 我已经确认这会在中间某处打印出 END。运行后检查脚本的输出:paste.ubuntu.com/10501008。 END 在第 553 行。
  • @dopstar 我看到了你的打印(谢谢!),结果对我来说没问题:'END'消息在'Out:Process-x'之后(并且在'Process -x - xxxxx' 个)。但是,在我的情况下,“Out:Process-x”消息是最后一个!没有“结束”:我有 (+/-) 500 个打印而不是 1000。可能是 Windows 配置问题...

标签: python python-3.x multiprocessing


【解决方案1】:

来自Queuedocumentation

如果可选的 args block 为 true 并且 timeout 为 None(默认值),则在必要时阻止,直到项目可用为止。

这意味着你的循环永远不会终止。

您需要在get 中添加超时并在收到Empty 异常时停止循环,或者您需要在收到STOP 消息时退出循环。

【讨论】:

  • 当然,少数 URLS 可以工作。我使用流程只是为了学习。我测试了一些日志记录,似乎所有 URL 都已处理但该过程似乎没有加入。
  • 在连接周围添加print 语句以查看哪个进程没有返回。您是如何检查每个 URL 是否被处理的?肉眼无法检查 1000 个 URL。
  • 我测试了所有处理过的 URL 和所有 'print("Out : %s " % (current_process().name))' 行。似乎所有进程都没有回来
  • 我认为他们正在等待您阅读他们的标准输出。您在进程中使用print。这意味着他们写入标准输出。
  • 我不认为:我在问题发生后添加了“打印”来跟踪。
【解决方案2】:

好的,我找到了答案(在 Python 文档中:https://docs.python.org/3.4/library/multiprocessing.html#multiprocessing-programming):

警告如上所述,如果子进程将项目放在 队列(并且它没有使用 JoinableQueue.cancel_join_thread),然后 直到所有缓冲的项目都已完成,该过程才会终止 冲入管道。

所以修改代码:

    print("Out : %s " % (current_process().name))
    return True

作者:

    print("Out : %s " % (current_process().name))
    done_queue.cancel_join_thread()
    return True

我不明白为什么初始代码适用于少量 URL...

【讨论】:

    猜你喜欢
    • 2015-08-28
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 2020-09-11
    • 2016-06-03
    • 2020-03-19
    相关资源
    最近更新 更多