【问题标题】:Can't pause python process using debug无法使用调试暂停 python 进程
【发布时间】:2023-01-30 00:04:16
【问题描述】:

我有一个 python 脚本,它使用这些行启动多个子进程:

for elm in elements:
    t = multiprocessing.Process(target=sub_process,args=[elm])
    threads.append(t)
    t.start()

for t in threads:
   t.join()

有时,由于某种原因线程停止并且脚本永远不会完成。 我正在尝试使用 VSCode 调试器来查找问题并检查它卡在线程本身的位置,但是我在暂停这些子进程时遇到问题,因为当我在调试器窗口中单击暂停时:

它会暂停主线程和其他一些正常运行的线程,但不会暂停卡住的子进程。 即使当我尝试使用“调用堆栈”窗口一个一个地手动暂停线程时,我仍然只能暂停工作线程而不是卡住的线程。

请帮我弄清楚这件事,这是一件很难的事情,因为使进程卡住的事情并不总是发生,因此很难调试。

【问题讨论】:

  • 您能否发布错误消息,就好像它正在运行那么多子进程一样,那么它可能是硬件限制,这可以解释为什么您会努力暂停子进程
  • @SophieOH 没有错误消息,这就是问题所在。但是我开始记录每一行,当我尝试获取信号量时,我发现它可能卡住了。
  • 请问edit这个问题能否明确区分线程和进程?您的描述以子流程有问题开始,然后说 dir example “我仍然只能暂停工作线程而不是卡住的线程。”暗示您的问题出在线程上。(粗略地)知道进程/线程在做什么也很有帮助-例如,它们是使用编译代码(例如numpy)运行计算还是纯Python,做他们依赖外部资源,如分布式文件系统或网络?
  • 不幸的是,回答您的问题并不能解决您的问题。这将需要访问更多代码。

标签: python vscode-debugger


【解决方案1】:

首先,那些是子进程,而不是线程。理解很重要 区别,虽然它没有回答你的问题。

其次,Python 调试器中的暂停(手动中断)将中断 Python 代码。 它惯于在下面执行 Python 的机器代码中打断,或者在机器中打断 下面的代码执行 Python 代码要求的操作系统服务。

如果执行暂停,暂停将发生在上面的Python代码中 当(如果)机器代码返回到 Python 解释器循环时的机器代码。

给出一个完整的例子:

import multiprocessing
import time

elements = ["one", "two", "three"]

def sub_process(gs, elm):
    gs.acquire()
    print("sleep", elm)
    time.sleep(60)
    print("awake", elm);
    gs.release()

def test():
    gs = multiprocessing.Semaphore()

    subprocs = []

    for elm in elements:
        p = multiprocessing.Process(target=sub_process,args=[gs, elm])
        subprocs.append(p)
        p.start()

    for p in subprocs:
        p.join()

if __name__ == '__main__':
    test()

第一个子进程将获取信号量并休眠一分钟, 第二个和第三个子进程将在gs.acquire() 中等待,直到它们 可以前进。暂停不会打断调试器,直到 subprocess 从 acquire 返回,因为 acquire 在 Python 代码下面。

听起来你知道这个过程在哪里卡住了, 但你不知道为什么。你需要确定哪些问题 你正在尝试回答。例如:

(假设)其中一个进程卡在获取中。这意味着另一个 进程没有释放信号量。哪个进程是什么代码 获取信号量而不释放它?

查看信号量对象本身可能会告诉您哪个子进程持有它, 但这是一个切线:你能用调试器检查信号量吗 并确定谁持有它?例如,在 Windows 中使用机器级调试器, 如果这些是线程和临界区,则可以查看临界区 并查看哪个线程仍在持有它。我不知道这是否可能 在您选择的平台上使用进程和信号量完成。

您有权访问哪些调试器取决于您运行的平台。

总之:

  • 您无法在机器代码中破坏 Python 调试器
  • 您可以在机器代码调试器中运行 Python 解释器,但这 根本不会向您展示 Python 代码,这让生活变得有趣。 这个能够如果您知道自己在寻找什么,请提供帮助 - 例如,您可能知道自己在等待信号量时卡住了。
  • 运行机器代码调试器时,运行变得更加困难 子流程,因为您需要知道您对哪个子流程感兴趣 在,并附加到那个。如果您使用单个,这会变得更简单 进程和多个线程,因为只有一个进程需要处理。

“你不能从这里去,你得先去别的地方。”

您需要仔细查看您的代码并弄清楚如何 使用其他方式回答您需要回答的问题。

【讨论】:

  • 要找出哪个子进程持有信号量或锁,您只需在关键部分的开头添加调试打印 - 最后打印的 (flush=True) 带有子进程标识符的行应该与卡住的行相对应。
【解决方案2】:

这只是一个想法,为什么不在您的子进程上设置 timeout 并终止它呢?

TIMEOUT = 60

for elm in elements:
    t = multiprocessing.Process(target=sub_process,args=[elm])
    t.daemon = True
    threads.append(t)
    t.start()
    t.join(TIMEOUT)

for t in threads:
   t.join()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-20
    • 1970-01-01
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多