Linux上多进程的进程终止失败

6

我刚刚注意到在Linux上使用multiprocessing库的terminate方法存在问题。我的应用程序使用multiprocessing库,但是...当我在Windows上调用terminate函数时,一切都很正常,但是在Linux上却失败了。作为进程终止的替代方案,我被迫使用

os.system('kill -9 {}'.format(pid))

我知道这并不太聪明,但它却行得通。我只是想知道为什么这段代码在Windows上可以运行,但在Linux上失败了。
示例:
from multiprocessing import Process
import os

process=Process(target=foo,args=('bar',))
pid=process.pid
process.terminate() # works on Windows only

...

os.sytem('kill -9 {}'.format(pid)) # my replacements on Linux

我的配置:python 3.2.0 版本 88445;Linux-2.6.32-Debian-6.0.4

这是我代码中的一个示例,希望它足够清晰明了。

def start_test(timestamp,current_test_suite,user_ip):
    global_test_table[timestamp] = current_test_suite
    setattr(global_test_table[timestamp], "user_ip", user_ip)
    test_cases = global_test_table[timestamp].test_cases_table

    test_cases = test_cases*int(global_test_table[timestamp].count + 1)
    global_test_table[timestamp].test_cases_table = test_cases
    print(test_cases)
    print(global_test_table[timestamp].test_cases_table)

    case_num = len(test_cases)
    Report.basecounter = Report.casecounter = case_num

    setattr(global_test_table[timestamp], "case_num", case_num)
    setattr(global_test_table[timestamp], "user_current_test", 0)

    try:
        dbobj=MySQLdb.connect(*dbconnector)
        dbcursor=dbobj.cursor()

        dbcursor.execute(sqlquery_insert_progress.format(progress_timestamp = str(timestamp), user_current_test = global_test_table[timestamp].user_current_tes$
    except :...

    for i in range(case_num):
        user_row = global_test_table[timestamp]
        current_test_from_tests_table = user_row.test_cases_table[i]
        unittest.TextTestRunner(verbosity=2).run(suite(CommonGUI.get_address(CommonGUI,current_test_from_tests_table[1], current_test_from_tests_table[2], user$
        global_test_table[timestamp].user_current_test = i + 1
        try:
            dbobj=MySQLdb.connect(*dbconnector)
            dbcursor=dbobj.cursor()

            dbcursor.execute(sqlquery_update_progress.format(progress_timestamp = str(timestamp), user_current_test = global_test_table[timestamp].user_current$
        except :...

@cherrypy.expose()
def start_test_page(self, **test_suite):
    timestamp = str(time.time())
    user_ip = cherrypy.request.remote.ip
    if on_server():
        sys.stdout=sys.stderr=open("/var/log/cherrypy/test_gui/{file}.log".format(file=timestamp),"a")
    current_test_suite = self.parse_result(**test_suite)
    #global_test_table[timestamp] = current_test_suite
    #setattr(global_test_table[timestamp], "user_ip", user_ip)
    user_test_process = Process(target=start_test, args=(timestamp,current_test_suite,user_ip))
    users_process_table[timestamp] = user_test_process
    user_test_process.start()
    return '''{"testsuite_id" : "''' + str(timestamp) + '''"}'''

@cherrypy.expose()
def stop_test(self, timestamp):
    if timestamp in users_process_table:
        if on_server():
            user_process_pid = users_process_table[timestamp].pid
            os.system("kill -9 " + str(user_process_pid))
        else:
            users_process_table[timestamp].terminate()
        del users_process_table[timestamp]
    else:
        return "No process exists"

你能贴出更多的代码吗?了解foo正在如何与bar进行交互将会有所帮助,从而我们可能会更好地理解为什么Linux没有成功,而Windows却做到了。 - parselmouth
2个回答

5

文档中可以看出:

terminate()

终止进程。在Unix上,使用SIGTERM信号实现;在Windows上,则使用TerminateProcess()函数。请注意,退出处理程序和finally子句等内容将不会执行。

请注意,进程的后代进程将不会被终止,它们只会变成孤儿进程。

因此,您需要确保进程正确处理SIGTERM信号。

使用signal.signal设置信号处理程序。

要设置一个简单地退出进程的SIGTERM信号处理程序,请使用以下代码:

import signal
import sys
signal.signal(signal.SIGTERM, lambda signum, stack_frame: sys.exit(1))

编辑

Python 进程通常会在收到 SIGTERM 信号后终止,我不知道为什么你的多进程处理程序没有在收到 SIGTERM 信号后终止。


0

虽然这不是你问题的直接答案,但由于你正在处理线程,这也可能对调试这些线程有所帮助: https://dev59.com/6HVC5IYBdhLWcg3w-WOs#10165776 我最近使用这段代码发现了cherrypy中的一个bug。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接