我在线程内部运行了以下代码。'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'值为空字符串。有人请建议一种方法在多线程环境中为每次运行获得一致的行为/输出?
答案 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”,并且可能解决方案以避免这种情况..
可能的问题:
以上建议的解决方案是:
理解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程序可能是一个很好的练习。