我在线程内部运行以下代码。." executable"为每个输入" 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在多次运行中也不一致),并以'error'值作为空字符串返回'-11'作为返回码。有人可以建议一种方法 在多线程环境中每次运行都能获得一致的行为/输出?
一般而言,我们需要有关您的可执行文件和python程序的更多信息。听起来好像做错了什么。您确定发送的网址正确返回了吗?您可以直接在python中执行可执行文件的操作吗?然后,您可以使用多重处理模块。
@WilliamDenman:hi..executable是一个C程序二进制文件,它在stdout上为给定的输入url生成JSON字符串输出..其余的python代码只是解析该输出字符串..让我知道您是否需要更多信息。
@WilliamDenman我可以肯定C可执行二进制文件可以正常工作,就像在串行执行的情况下一样,每个URL生成的输出是一致的。我无法用python代码替换C可执行文件。
"打印"不是线程安全的...
如何执行多个输入网址。请输入您如何执行此操作的完整代码。您在问题中遇到的方式p.communicate()将阻塞,直到该过程完成为止,因此不会并行执行任何工作。
@dbra:嗨..任何解决该问题的方法在python中?
@WilliamDenman:我是这样做的:urls = [url1,url2,url3] for url in urls: Worker(url) Worker是执行问题中提到的代码的线程..您对p.communicate是正确的..您可能会注意到这里..我并行完成工作因为每个线程执行单个子流程实例,该实例处理分配给该特定线程的单个url。
@SagarG:您可以将输出推送到队列(列表)上,并使用额外的线程进行打印,或者可以使用信号量同步打印,或者可以使用原子AFAIK的sys.stdout.write。
@dbra:问题似乎不是由于打印不是线程安全的。.因为当我将每个线程的输出记录到文件中时..每个输出都正确地写入了(不必担心顺序)输出)..即使对于失败的URL,我也看到异常消息被写入..
您确实需要在问题中包含完整的代码。我觉得@dbra在正确的轨道上。但是,如果没有定义Worker函数,我们实际上只是在猜测一个解决方案。
@WilliamDenman:请看下面"塞巴斯蒂安"提到的代码。它产生-11作为少数子流程的return_code。我现在试图找出是什么原因导致子流程返回-11。是C可执行文件还是python-multithreading。
我现在几乎可以肯定的是,您的C程序正在做一些奇怪的事情。您正在使用哪个版本的Python?尝试使用最新的3.2.x,看看是否得到相同的结果。您是否自己编写了C程序?如果不是,那么您将无法确定它没有执行线程安全的操作。
-11作为返回码可能意味着C程序不合适,例如,您启动了太多子进程,这会导致C可执行文件中出现SIGSERV。您可以使用multiprocessing.ThreadPool,current.futures.ThreadPoolExecutor,基于线程+基于队列的解决方案来限制并发子进程的数量:
#!/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
了解C ++中的SIGSEGV运行时错误是什么?简而言之,如果程序试图访问它不应该访问的内存,则该程序将被该信号杀死。这是此类程序的示例:
/* try to fail with SIGSERV sometimes */
#include
#include
#include
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
", *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获取回溯,以查看错误来自调用栈的何处。
我正在使用"使用Queue的子进程+线程(手动池)解决方案"方法。pool_size =100。请您解释一下有关"您启动了太多子进程,并在C可执行文件中导致SIGSERV"的问题,并可能提出解决方案 避免那样
我尝试了上面的代码,并确认它为几个子进程返回-11。对于失败的情况,输出和错误将输出空字符串。。print("%s %r %r %d" % (url, output, error, returncode))同样,p.returncode不足以用于调试。是否还有其他选项可以获取更多信息? 调试信息以获得根本原因?
@SagarG:Ive从评论中添加了对您问题的答案。
返回代码-11似乎表明您的C程序不正确。
通常,如果您尝试使用多个线程,则应确切了解所调用程序的实现方式。如果没有,您将遇到类似这样的奇怪而晦涩的错误。
如果您无权访问C可执行文件的源代码,则要么必须用C编写自己的线程安全版本,要么我建议将外部程序实现为Python函数。然后,您可以将其与multiprocessing模块并行化。
Python非常擅长创建和分析JSON,重新实现C程序可能是一个不错的练习。