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

时间:2013-11-18 13:28:40

标签: python multithreading subprocess popen

我在线程内部运行了以下代码。'executable'为每个输入'url'生成唯一的字符串输出:

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

当上面的代码被执行多个输入'urls'时,产生的子进程p''output'不一致。对于一些url,子进程终止而不产生任何'output'。我尝试为每个失败的'p'实例打印p.returncode(失败的网址在多次运行中都不一致)并得到'-11'作为返回代码,其中'error'值为空字符串。有人请建议一种方法在多线程环境中为每次运行获得一致的行为/输出?

2 个答案:

答案 0 :(得分:1)

-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

  

请你详细解释一下“你正在启动太多的子进程并且它会导致C可执行文件中的SIGSERV”,并且可能解决方案以避免这种情况..

可能的问题:

  • “过多的过程”
  • - > “系统中没有足够的内存或其他资源”
  • - > “触发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

  

p.returncode也不足以用于调试目的..是否还有其他选项可以获得更多DEBUG信息以找到根本原因?

我不会完全排除Python方面,但问题很可能是C程序。您可以使用gdb to get a backtrace查看错误来自callstack的位置。

答案 1 :(得分:0)

-11的返回代码似乎表明您的C程序出现了问题。

通常,如果您尝试使用多个线程,您应该确切地知道您正在调用的程序是如何实现的。如果没有,你会遇到像这样的奇怪和模糊的错误。

如果您无法访问C可执行文件的源代码,您将需要在C中编写自己的线程安全版本,或者我建议在Python中实现外部程序作为函数即可。然后,您可以将其与multiprocessing模块并行化。

Python非常擅长创建和分析JSON,重新实现C程序可能是一个很好的练习。