探究 sleep(0) 和 sched_yield()
先放結論:
- sleep(0) 和 sched_yield() 都能起到讓系統調度的作用
- 如果業務吞吐量不高,且需要降低CPU使用率時,可以使用 sleep(0)
- 在需要保證響應速度的情況下,可以使用 sched_yield()
問題起因
在使用 epoll_wait 時,發現運行期間,CPU的使用率達到了 100%,風扇一直響。
如果長時間沒有就緒事件,其實就相當于出現了 busy wait。這種情況下需要及時的讓權,以給予其他進程更多的運行機會,常用的方案有兩種:
- sleep(0)
- sched_yield()
sched_yield() 其實好理解,就是讓進程顯式地將處理器時間讓給其他等待執行進程的機制。它是通過將進程從活動隊列移動到過期隊列中實現的。由于實時進程不會過期,因此,只是將其移動到活動隊列的最后面。
其實,sleep(0) 在 windows 中經常使用,MSDN這樣解釋:
A value of zero causes the thread to relinquish the remainder of its time slice to any other thread that is ready to run. If there are no other threads ready to run, the function returns immediately, and the thread continues execution.
那么問題來了:
- 在 Linux 中 sleep(0) 是否也能起到相應作用?
- sleep(0) 和 sched_yield() 的區別是什么?
測試
使用如下代碼測試 sleep(0) 和 sched_yield() 的作用。運行時間是測試運行 1e5 次的所需時間。CPU 使用率是在while(1) 循環下測得。
以下數據均為同一臺電腦測試得到。
結果如下:
| sleep(0) | 9.501s | 38.5% |
| sched_yield() | 0.080s | 99.7% |
| 空語句 | 0.006s | 99.7% |
從上表可以看出,sleep(0)運行時間比sched_yield() 多出兩個數量級。
- sleep(0) 是否引起了系統調度?
- 為什么 sleep(0) 會比 sched_yield() 慢這么多?
通過 trace 程序的具體執行過程來解釋問題
這里使用 trace-cmd,他可以跟蹤系統調用。
通過以下命令來查看具體的執行過程
兩種情況的執行過程如下:
sleep(0) 的單次執行過程。
為了方便觀看,省略了一部分子過程。
trace report 的結果里,會在大于10微秒前添加 “+” 號,在大于100微秒的前面添加 “!” 號。
可以看到:
- sleep 的執行實際是調用了 hrtimer_nanosleep()。即使參數是0,也完整調用了整個過程,沒有像windows 中的那樣對 0 值進行優化,耗時明顯。
- sleep 過程中觸發了系統的調度。但是系統調度會將進程從紅黑樹中移出,并放入等待隊列。這個過程耗時明顯。
- 調度更像是進程休眠之后造成的結果。
sched_yield() 的單次執行過程。
該子過程沒有刪減。只有一個schedule(), 整個過程簡潔清晰。
| __do_sys_sched_yield() {| do_sched_yield() {0.132 us | _raw_spin_lock();0.128 us | yield_task_fair();| schedule() {| rcu_note_context_switch() {0.125 us | rcu_qs();0.382 us | }0.125 us | _raw_spin_lock();0.139 us | update_rq_clock();| pick_next_task_fair() {| update_curr() {0.123 us | update_min_vruntime();0.382 us | }0.129 us | check_cfs_rq_runtime();| pick_next_entity() {0.133 us | clear_buddies();0.413 us | }| update_curr() {0.122 us | update_min_vruntime();| cpuacct_charge() {0.131 us | rcu_read_unlock_strict();0.396 us | }| __cgroup_account_cputime() {0.129 us | cgroup_rstat_updated();0.380 us | }0.128 us | rcu_read_unlock_strict();1.695 us | }0.126 us | check_cfs_rq_runtime();| pick_next_entity() {0.140 us | clear_buddies();0.407 us | }4.056 us | }5.350 us | }6.127 us | }6.485 us | }結論
- sleep(0) 和 sched_yield() 都能起到讓系統調度的作用,sleep(0) 更耗時
- 如果業務吞吐量不高,且需要降低CPU使用率時,可以使用 sleep(0)
- 在需要保證響應速度的情況下,使用 sched_yield()
參考:
- sleep(0)、usleep(0)與sched_yield() 調度
- APPENDIX B. DETAILED DESCRIPTION OF FTRACE
- Linux內核設計與實現
總結
以上是生活随笔為你收集整理的探究 sleep(0) 和 sched_yield()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电子货架标签-----智能基站V3
- 下一篇: C#文件读取