我有一个有两个线程的进程。
第一个线程正在执行异步工作 - 它在epoll_wait
中等待描述符和计时器事件上的IO。
第二个线程正在进行大量的IO /内存工作 - 它从磁盘读取数据,在内存中处理数据,分配大量新内存,将其写入磁盘等等。
问题是epoll_wait
中的第一个线程阻塞的时间要长得多,然后在epoll_wait
的超时时间内被请求(例如,超时被指定为1500毫秒并实际从epoll_wait
返回在10秒内。)
这种行为我可以在虚拟机中可靠地重现(VirtualBox with Ubuntu 16.04)。
来自GDB
的行为示例:
Thread 2.1 "se.real" hit Breakpoint 1, boost::asio::detail::epoll_reactor::run (this=0x826ebe0, block=true, ops=...) at /opt/com/include/boost/158/boost/asio/detail/impl/epoll_reactor.ipp:392
392 in /opt/com/include/boost/158/boost/asio/detail/impl/epoll_reactor.ipp
16:36:38.986826839
$17 = 1945
Thread 2.1 "se.real" hit Catchpoint 3 (call to syscall epoll_wait), 0xf7fd8be9 in __kernel_vsyscall ()
16:36:38.992081396
<INSIDE KERNEL>
Thread 2.1 "se.real" hit Catchpoint 3 (returned from syscall epoll_wait), 0xf7fd8be9 in __kernel_vsyscall ()
16:36:54.681444938
断点1设置为call epoll_wait
之前的指令,打印参数为超时参数值(1945 ms)。
打印时间是shell date +"%T.%N"
命令的时间。
Catchpoint 3是epoll_wait
系统调用的系统调用捕获点(第一个用于输入,第二个用于返回)。
我们可以很容易地看到我们在内核中花了大约16秒,当时请求了1945毫秒。
我收集了perf record
来自其他复制品的-e 'sched:*'
个事件。我完全看到了:
se.real 4277 [001] 113049.144027: sched:sched_switch: prev_comm=se.real prev_pid=4277 prev_prio=120 prev_state=t|K ==> next_comm=strace next_pid=4142 next_prio=120
se.real 4277 [001] 113056.407952: sched:sched_stat_runtime: comm=se.real pid=4277 runtime=153767 [ns] vruntime=409222246640 [ns]
对于线程4277(具有异步IO和epoll_wait
的第一个线程)没有任何其他sched事件约7秒。与此同时,这些事件之间有大量的计划活动。此活动包括第二个线程(具有大量IO /内存工作的线程),swapper
/ kswapd
以及其他用户空间进程。
问题是我能做些什么才能有机会运行第一个线程?
更新:将流程的调度策略更改为SCHED_FIFO
无法解决问题 - 我仍然可以稳定地重现此问题。