我有一个Python程序(确切地说,是一个Django应用程序),它使用^{
相反,当子进程启动时,我必须将进程id pid
写入文件pidfile
。当我想停止子进程时,我打开这个pidfile
,并使用^{
我的问题是:如何确定子流程何时真正终止?使用signal.SIGTERM
调用os.kill()
后,需要大约1-2分钟才能最终终止。首先我认为^{os.kill()
之后调用它时,它给了我OSError: [Errno 10] No child processes
。
顺便说一下,我使用两个表单从HTML模板启动和停止子流程,程序逻辑在Django视图中。当应用程序处于调试模式时,异常将显示在浏览器中。了解我在视图中调用的子进程(python manage.py crawlwebpages
)本身调用另一个子进程,即Scrapy爬虫的一个实例,可能也很重要。我将这个Scrapy实例的pid
写入pidfile
,这就是我想要终止的。
以下是相关代码:
def process_main_page_forms(request):
if request.method == 'POST':
if request.POST['form-type'] == u'webpage-crawler-form':
template_context = _crawl_webpage(request)
elif request.POST['form-type'] == u'stop-crawler-form':
template_context = _stop_crawler(request)
else:
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': StopCrawlerForm()}
return render(request, 'main.html', template_context)
def _crawl_webpage(request):
webpage_crawler_form = WebPageCrawlerForm(request.POST)
if webpage_crawler_form.is_valid():
url_to_crawl = webpage_crawler_form.cleaned_data['url_to_crawl']
maximum_pages_to_crawl = webpage_crawler_form.cleaned_data['maximum_pages_to_crawl']
program = 'python manage.py crawlwebpages' + ' -n ' + str(maximum_pages_to_crawl) + ' ' + url_to_crawl
p = subprocess.Popen(program.split())
template_context = {
'webpage_crawler_form': webpage_crawler_form,
'stop_crawler_form': StopCrawlerForm()}
return template_context
def _stop_crawler(request):
stop_crawler_form = StopCrawlerForm(request.POST)
if stop_crawler_form.is_valid():
with open('scrapy_crawler_process.pid', 'rb') as pidfile:
process_id = int(pidfile.read().strip())
print 'PROCESS ID:', process_id
os.kill(process_id, signal.SIGTERM)
os.waitpid(process_id, os.WNOHANG) # This gives me the OSError
print 'Crawler process terminated!'
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': stop_crawler_form}
return template_context
我能做什么?非常感谢你!
编辑:
根据Jacek Konieczny给出的the great answer,我可以通过将函数_stop_crawler(request)
中的代码更改为以下内容来解决我的问题:
def _stop_crawler(request):
stop_crawler_form = StopCrawlerForm(request.POST)
if stop_crawler_form.is_valid():
with open('scrapy_crawler_process.pid', 'rb') as pidfile:
process_id = int(pidfile.read().strip())
# These are the essential lines
os.kill(process_id, signal.SIGTERM)
while True:
try:
time.sleep(10)
os.kill(process_id, 0)
except OSError:
break
print 'Crawler process terminated!'
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': stop_crawler_form}
return template_context
我的解决方案是放置一个控制子流程的中间流程。
因此,您的web请求(由于并行化,这些请求似乎都发生在不同的进程中?)告诉控制过程启动一个给定的程序并观察它;一旦需要,他们就会询问状态是什么。
在最简单的情况下,这个进程将是一个打开UNIX域套接字(也可以是TCP/IP套接字)并监听它的进程。“web进程”连接到它,发送启动请求并返回一个唯一的ID。然后,它可以使用这个ID对新进程进行进一步的查询。
或者,它自己给出ID(或者如果只有一个进程,它根本不使用ID),因此不必保留一些变量ID。
检查进程是否仍在运行的通常方法是用信号“0”终止它。它对正在运行的作业没有任何作用,如果进程不存在,则引发
OSError
异常和errno=ESRCH
。但只要可能,调用方就应该保持被调用进程的父进程,并使用
wait()
函数族来处理其终止。这就是Popen
对象所做的。相关问题 更多 >
编程相关推荐