Skip to main content
 首页 » 编程设计

Python-Subprocess-Popen 在多线程环境下的不一致行为

2025年05月04日33qq号

我在线程中运行了以下代码。“可执行”为每个输入“url”生成唯一的字符串输出:

p = Popen(["executable", url], stdout=PIPE, stderr=PIPE, close_fds=True) 
output,error = p.communicate() 
print output 

当针对多个输入“url”执行上述代码时,子进程 p 产生的“输出”不一致。对于某些 url,子进程在没有产生任何“输出”的情况下终止。我尝试为每个失败的 'p' 实例打印 p.returncode(失败的 url 在多次运行中也不一致)并得到 '-11' 作为返回码,'error' 值为空字符串。有人可以建议一种方法来在多线程环境中为每次运行获得一致的行为/输出?

请您参考如下方法:

-11 作为返回码可能意味着 C 程序不正常,例如,您启动了太多子进程,它会导致 C 可执行文件中出现 SIGSERV。您可以使用 multiprocessing.ThreadPool, concurrent.futures.ThreadPoolExecutor, threading + Queue -based solutions 限制并发子进程的数量:

#!/usr/bin/env python 
from multiprocessing.dummy import Pool # uses threads 
from subprocess import Popen, PIPE 
 
def get_url(url): 
    p = Popen(["executable", url], stdout=PIPE, stderr=PIPE, close_fds=True) 
    output, error = p.communicate() 
    return url, output, error, p.returncode 
 
pool = Pool(20) # limit number of concurrent subprocesses 
for url, output, error, returncode in pool.imap_unordered(get_url, urls): 
    print("%s %r %r %d" % (url, output, error, returncode)) 

确保可执行文件可以并行运行,例如,它不使用某些共享资源。要进行测试,您可以在 shell 中运行:

$ executable url1 & executable url2 

Could you please explain more about "you are starting too many subprocesses and it causes SIGSERV in the C executable" and possibly solution to avoid that..

可能的问题:

  • “进程太多”
  • ->“系统内存或其他资源不足”
  • ->“触发 C 代码中隐藏或罕见的错误”
  • ->“非法内存访问”
  • ->SIGSERV

上面建议的解决方案是:

  • “限制并发进程数”
  • ->“系统中有足够的内存或其他资源”
  • ->“错误是隐藏的或罕见的”
  • -> 没有 SIGSERV

了解what is SIGSEGV run time error in c++?简而言之,如果您的程序试图访问不应该访问的内存,它就会被该信号杀死。这是此类程序的示例:

/* try to fail with SIGSERV sometimes */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
 
int main(void) { 
  char *null_pointer = NULL; 
 
  srand((unsigned)time(NULL)); 
 
  if (rand() < RAND_MAX/2) /* simulate some concurrent condition  
                              e.g., memory pressure */ 
    fprintf(stderr, "%c\n", *null_pointer); /* dereference null pointer */ 
 
  return 0; 
} 

如果您使用上述 Python 脚本运行它,那么它偶尔会返回 -11。

Also p.returncode is not sufficient for debugging purpose..Is there any other option to get more DEBUG info to get to the root cause?

我不会完全排除 Python 方面,但问题很可能是 C 程序。你可以使用 gdb to get a backtrace查看错误来自调用堆栈中的何处。