diff --git a/judge/client.py b/judge/client.py index 8302f759..c9ff7338 100644 --- a/judge/client.py +++ b/judge/client.py @@ -2,11 +2,32 @@ import json import time import commands -from Queue import Queue -from thread_pool import ThreadPool +from multiprocessing import Pool from settings import max_running_number, lrun_gid, lrun_uid, use_tmpfs from consts import Language, Result +from copy_reg import pickle +from types import MethodType + + +# 下面两个函数告诉Python怎么pickle类实例中的方法,否则Python2会报错,是Python2的已知bug +def _pickle_method(method): + func_name = method.im_func.__name__ + obj = method.im_self + cls = method.im_class + return _unpickle_method, (func_name, obj, cls) + + +def _unpickle_method(func_name, obj, cls): + for cls in cls.mro(): + try: + func = cls.__dict__[func_name] + except KeyError: + pass + else: + break + return func.__get__(obj, cls) + class JudgeClientException(Exception): pass @@ -15,24 +36,25 @@ class JudgeClientException(Exception): class JudgeClient(object): def __init__(self, language, exec_file_path, max_cpu_time, max_real_time, max_memory, test_case_dir): - # 语言 c cpp 或者 java + """ + :param language: 语言,见consts.py + :param exec_file_path: 可执行文件路径 + :param max_cpu_time: 最大cpu时间,单位ms + :param max_real_time: 最大执行时间,单位ms + :param max_memory: 最大内存,单位MB + :param test_case_dir: 测试用户文件夹路径 + :return:返回结果list + """ self.language = language - # 可执行文件路径,比如 /root/1/a.out /root/1/Main.class self.exec_file_path = exec_file_path - # 最大的cpu时间 单位ms self.max_cpu_time = max_cpu_time - # 最大实际运行时间 单位ms self.max_real_time = max_real_time - # 最大cpu占用,注意不要小于500000 单位byte self.max_memory = max_memory - # 测试用例文件路径,比如/root/testcase/1/ self.test_case_dir = test_case_dir - # 判题结果队列 - self.result_queue = Queue() - # 线程池 - self.thread_pool = ThreadPool(size=max_running_number, - result_queue=self.result_queue) - self.thread_pool.start() + # 进程池 + self.pool = Pool(processes=max_running_number) + # 结果数组 + self.results = [] # 测试用例配置项 self.test_case_info = self.load_test_case_info() @@ -67,9 +89,9 @@ class JudgeClient(object): # todo 系统调用白名单 chroot等参数 # fixme 时间的单位问题 command = "lrun" + \ - " --max-cpu-time " + str(self.max_cpu_time) + \ - " --max-real-time " + str(self.max_real_time) + \ - " --max-memory " + str(self.max_memory) + \ + " --max-cpu-time " + str(self.max_cpu_time / 1000.0) + \ + " --max-real-time " + str(self.max_real_time / 1000.0) + \ + " --max-memory " + str(self.max_memory * 1000 * 1000) + \ " --network false" + \ " --uid " + str(lrun_uid) + \ " --gid " + str(lrun_gid) @@ -98,6 +120,8 @@ class JudgeClient(object): "CPU_TIME": "cpu_time", "REALTIME": "real_time", "REAL_TIME": "real_time", + "TERMSIG": "term_sig", + "SIGNALED": "siginaled", "EXITCODE": "exit_code", "EXCEED": "exceed"} for line in lines: @@ -112,6 +136,10 @@ class JudgeClient(object): result[translate[name]] = float(value) * 1000 elif name == "EXITCODE": result[translate[name]] = int(value) + elif name == "TERMSIG": + result[translate[name]] = int(value) + elif name == "SIGNALED": + result[translate[name]] = int(value) elif name == "EXCEED": if value == "none": result[translate[name]] = None @@ -130,7 +158,7 @@ class JudgeClient(object): run_result["test_case_id"] = test_case_id # 如果返回值非0,代表非正常结束 - if run_result["exit_code"]: + if run_result["exit_code"] or run_result["term_sig"] or run_result["siginaled"]: run_result["result"] = Result.RUNTIME_ERROR return run_result @@ -148,22 +176,30 @@ class JudgeClient(object): run_result["result"] = Result.ACCEPTED return run_result + def collect_result(self, result): + self.results.append(result) + def run(self): # 添加到任务队列 for i in range(self.test_case_info["test_case_number"]): - self.thread_pool.append_job(self.judge_one, i + 1) + self.pool.apply_async(self.judge_one, args=(i + 1, ), + callback=self.collect_result) + self.pool.close() + self.pool.join() + print self.results - self.thread_pool.join() - self.thread_pool.stop() - - for i in range(self.test_case_info["test_case_number"]): - print self.result_queue.get(block=False) + def __getstate__(self): + # 不同的pool之间进行pickle的时候要排除自己,否则报错 + self_dict = self.__dict__.copy() + del self_dict['pool'] + return self_dict +pickle(MethodType, _pickle_method, _unpickle_method) client = JudgeClient(language=Language.C, exec_file_path="/var/judge/a.out", - max_cpu_time=1000, - max_real_time=2000, - max_memory=600000, + max_cpu_time=1000000, + max_real_time=200000, + max_memory=1, test_case_dir="/var/test_case/1/") client.run()