-
Notifications
You must be signed in to change notification settings - Fork 12
HolyShit
这里记录的是一些踩坑的记录,可能是已解决,也可能是没解决的问题。
由于go本身调度的问题,切记不要在协程里直接syscall.Fork()。踩过坑了,有源代码直接用它不香吗,这不是C语言!
用golang自带的syscall.ForkExec代码和os下的Process相关代码进行改动后封装成新的包即可解决问题。
v1版本判题判题机由两个模块组成,deer-executor提供判题流程的核心代码;deer-judger进行队列管理、评测调度和结果持久化操作等(内部项目,未开源)。判题机进程常驻在后台,直接在协程里fork运行目标程序。
在判题机运行了一段时间后(并判了一些题目后),会小概率出现fork失败的情况,判题机报SE,发起重判或者重启进程能解决这个问题。推测这个问题可能和go的协程管理或GC有关,因个人能力有限,具体是什么情况没能得出结论。

缓解:
v2判题机设计成独立运行的CLI,并且抽出了原deer-judger里的完整评测流程逻辑,每次需要的时候执行就行,用完直接退出。驻留进程deer-judger将被修改成一个管理队列、调用CI、存储报告和通知OJ的工具,不再执行判题相关操作。
利用docker的reexec包执行自己后,发现时间判定和内存判定都较之前版本的有所偏差,一个hello_world.c的时间在4-5ms左右,内存大概要4MB。初步怀疑是因为reexec是重新执行go程序,然后执行到其他分支去来模拟fork的,不是单纯的fork,故这边有所消耗。
尝试用一个文件,在syscall.Exec之前记录当前进程的rusage,后在判题机程序内减去,这种情况下内存基本正常,但是时间不稳定, Mac下恒定在2ms,Linux下在0ms和4ms下反复横跳。说明这种修正方式是不正确的,getrusage不能准确的获取当前程序的执行时间。
决定:改回去用以前的那种fork形式了,这次改动的代码放在v2_dev_obsolete分支(已删除)。
© 2018 - 2021 LanceLRQ,All rights reserved.