32 | 答疑(四):阻塞、非阻塞 I/O 与同步、异步 I/O 的区别和联系
生活随笔
收集整理的這篇文章主要介紹了
32 | 答疑(四):阻塞、非阻塞 I/O 与同步、异步 I/O 的区别和联系
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
問(wèn)題 1:阻塞、非阻塞 I/O 與同步、異步 I/O 的區(qū)別和聯(lián)系
在文件系統(tǒng)的工作原理篇中,介紹了阻塞、非阻塞 I/O 以及同步、異步 I/O 的含義,這里我們?cè)俸?jiǎn)單回顧一下。
首先我們來(lái)看阻塞和非阻塞 I/O。根據(jù)應(yīng)用程序是否阻塞自身運(yùn)行,可以把 I/O 分為阻塞 I/O 和非阻塞 I/O。
- 所謂阻塞 I/O,是指應(yīng)用程序在執(zhí)行 I/O 操作后,如果沒(méi)有獲得響應(yīng),就會(huì)阻塞當(dāng)前線程,不能執(zhí)行其他任務(wù)。
- 所謂非阻塞 I/O,是指應(yīng)用程序在執(zhí)行 I/O 操作后,不會(huì)阻塞當(dāng)前的線程,可以繼續(xù)執(zhí)行其他的任務(wù)。
再來(lái)看同步 I/O 和異步 I/O。根據(jù) I/O 響應(yīng)的通知方式的不同,可以把文件 I/O 分為同步 I/O 和異步 I/O。
- 所謂同步 I/O,是指收到 I/O 請(qǐng)求后,系統(tǒng)不會(huì)立刻響應(yīng)應(yīng)用程序;等到處理完成,系統(tǒng)才會(huì)通過(guò)系統(tǒng)調(diào)用的方式,告訴應(yīng)用程序 I/O 結(jié)果。
- 所謂異步 I/O,是指收到 I/O 請(qǐng)求后,系統(tǒng)會(huì)先告訴應(yīng)用程序 I/O 請(qǐng)求已經(jīng)收到,隨后再去異步處理;等處理完成后,系統(tǒng)再通過(guò)事件通知的方式,告訴應(yīng)用程序結(jié)果。
你可以看出,阻塞 / 非阻塞和同步 / 異步,其實(shí)就是兩個(gè)不同角度的 I/O 劃分方式。它們描述的對(duì)象也不同,阻塞 / 非阻塞針對(duì)的是 I/O 調(diào)用者(即應(yīng)用程序),而同步 / 異步針對(duì)的是 I/O 執(zhí)行者(即系統(tǒng))。
我舉個(gè)例子來(lái)進(jìn)一步解釋下。比如在 Linux I/O 調(diào)用中,
- 系統(tǒng)調(diào)用 read 是同步讀,所以,在沒(méi)有得到磁盤數(shù)據(jù)前,read 不會(huì)響應(yīng)應(yīng)用程序。
- 而 aio_read 是異步讀,系統(tǒng)收到 AIO 讀請(qǐng)求后不等處理就返回了,而具體的 read 結(jié)果,再通過(guò)回調(diào)異步通知應(yīng)用程序。
再如,在網(wǎng)絡(luò)套接字的接口中,
- 使用 send() 直接向套接字發(fā)送數(shù)據(jù)時(shí),如果套接字沒(méi)有設(shè)置 O_NONBLOCK 標(biāo)識(shí),那么 send() 操作就會(huì)一直阻塞,當(dāng)前線程也沒(méi)法去做其他事情。
- 當(dāng)然,如果你用了 epoll,系統(tǒng)會(huì)告訴你這個(gè)套接字的狀態(tài),那就可以用非阻塞的方式使用。當(dāng)這個(gè)套接字不可寫的時(shí)候,你可以去做其他事情,比如讀寫其他套接字。
問(wèn)題 2:“文件系統(tǒng)”課后思考
最后,給你留一個(gè)思考題。在實(shí)際工作中,我們經(jīng)常會(huì)根據(jù)文件名字,查找它所在路徑,比如:find/-name file-name今天的問(wèn)題就是,這個(gè)命令,會(huì)不會(huì)導(dǎo)致系統(tǒng)的緩存升高呢?如果有影響,又會(huì)導(dǎo)致哪種類型的緩存升高呢?執(zhí)行 find 命令時(shí),會(huì)不會(huì)導(dǎo)致系統(tǒng)的緩存升高呢?如果會(huì)導(dǎo)致,升高的又是哪種類型的緩存呢?關(guān)于這個(gè)問(wèn)題,白華和 coyang 的答案已經(jīng)很準(zhǔn)確了。通過(guò)學(xué)習(xí) Linux 文件系統(tǒng)的原理,我們知道,文件名以及文件之間的目錄關(guān)系,都放在目錄項(xiàng)緩存中。而這是一個(gè)基于內(nèi)存的數(shù)據(jù)結(jié)構(gòu),會(huì)根據(jù)需要?jiǎng)討B(tài)構(gòu)建。所以,查找文件時(shí),Linux 就會(huì)動(dòng)態(tài)構(gòu)建不在緩存中的目錄項(xiàng)結(jié)構(gòu),導(dǎo)致 dentry 緩存升高。事實(shí)上,除了目錄項(xiàng)緩存增加,Buffer 的使用也會(huì)增加。如果你用 vmstat 觀察一下,會(huì)發(fā)現(xiàn) Buffer 和 Cache 都在增長(zhǎng):$ vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st0 1 0 7563744 6024 225944 0 0 3736 0 574 3249 3 5 89 3 01 0 0 7542792 14736 236856 0 0 8708 0 13494 32335 8 19 66 7 00 1 0 7494452 27280 272284 0 0 12544 0 4550 17084 5 15 68 13 00 1 0 7475084 42380 276320 0 0 15096 0 2541 14253 2 6 78 13 00 1 0 7455728 57600 280436 0 0 15220 0 2025 14518 2 6 70 22 0這里,Buffer 的增長(zhǎng)是因?yàn)?#xff0c;構(gòu)建目錄項(xiàng)緩存所需的元數(shù)據(jù)(比如文件名稱、索引節(jié)點(diǎn)等),需要從文件系統(tǒng)中讀取。問(wèn)題 3:“磁盤 I/O 延遲”課后思考
在磁盤 I/O 延遲案例的最后,我給你留了一道思考題。我們通過(guò) iostat ,確認(rèn)磁盤 I/O 已經(jīng)出現(xiàn)了性能瓶頸,還用 pidstat 找出了大量磁盤 I/O 的進(jìn)程。但是,隨后使用 strace 跟蹤這個(gè)進(jìn)程,卻找不到任何 write 系統(tǒng)調(diào)用。這是為什么呢?我們需要加 -f 選項(xiàng),以便跟蹤多進(jìn)程和多線程的系統(tǒng)調(diào)用情況。寫文件是由子線程執(zhí)行的,所以直接strace跟蹤進(jìn)程沒(méi)有看到write系統(tǒng)調(diào)用,可以通過(guò)pstree查看進(jìn)程的線程信息,再用strace跟蹤。或者,通過(guò)strace -fp pid 跟蹤所有線程。問(wèn)題 4:“MySQL 案例”課后思考
在 MySQL 案例的最后,我給你留了一個(gè)思考題。為什么 DataService 應(yīng)用停止后,即使仍沒(méi)有索引,MySQL 的查詢速度還是快了很多,并且磁盤 I/O 瓶頸也消失了呢?事實(shí)上,當(dāng)你看到 DataService 在修改 /proc/sys/vm/drop_caches 時(shí),就應(yīng)該想到前面學(xué)過(guò)的 Cache 的作用。我們知道,案例應(yīng)用訪問(wèn)的數(shù)據(jù)表,基于 MyISAM 引擎,而 MyISAM 的一個(gè)特點(diǎn),就是只在內(nèi)存中緩存索引,并不緩存數(shù)據(jù)。所以,在查詢語(yǔ)句無(wú)法使用索引時(shí),就需要數(shù)據(jù)表從數(shù)據(jù)庫(kù)文件讀入內(nèi)存,然后再進(jìn)行處理。所以,如果你用 vmstat 工具,觀察緩存和 I/O 的變化趨勢(shì),就會(huì)發(fā)現(xiàn)下面這樣的結(jié)果:$ vmstat 1procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st# 備注: DataService 正在運(yùn)行 0 1 0 7293416 132 366704 0 0 32516 12 36 546 1 3 49 48 00 1 0 7260772 132 399256 0 0 32640 0 37 463 1 1 49 48 00 1 0 7228088 132 432088 0 0 32640 0 30 477 0 1 49 49 00 0 0 7306560 132 353084 0 0 20572 4 90 574 1 4 69 27 00 2 0 7282300 132 368536 0 0 15468 0 32 304 0 0 79 20 0# 備注:DataService 從這里開(kāi)始停止0 0 0 7241852 1360 424164 0 0 864 320 133 1266 1 1 94 5 00 1 0 7228956 1368 437400 0 0 13328 0 45 366 0 0 83 17 00 1 0 7196320 1368 470148 0 0 32640 0 33 413 1 1 50 49 0 ...0 0 0 6747540 1368 918576 0 0 29056 0 42 568 0 0 56 44 00 0 0 6747540 1368 918576 0 0 0 0 40 141 1 0 100 0 0在 DataService 停止前,cache 會(huì)連續(xù)增長(zhǎng)三次后再降回去,這正是因?yàn)?DataService 每隔 3 秒清理一次頁(yè)緩存。而 DataService 停止后,cache 就會(huì)不停地增長(zhǎng),直到增長(zhǎng)為 918576 后,就不再變了。這時(shí),磁盤的讀(bi)降低到 0,同時(shí),iowait(wa)也降低到 0,這說(shuō)明,此時(shí)的所有數(shù)據(jù)都已經(jīng)在系統(tǒng)的緩存中了。我們知道,緩存是內(nèi)存的一部分,它的訪問(wèn)速度比磁盤快得多,這也就能解釋,為什么 MySQL 的查詢速度變快了很多。從這個(gè)案例,你會(huì)發(fā)現(xiàn),MySQL 的 MyISAM 引擎,本身并不緩存數(shù)據(jù),而要依賴系統(tǒng)緩存來(lái)加速磁盤 I/O 的訪問(wèn)。一旦系統(tǒng)中還有其他應(yīng)用同時(shí)運(yùn)行,MyISAM 引擎就很難充分利用系統(tǒng)緩存。因?yàn)橄到y(tǒng)緩存可能被其他應(yīng)用程序占用,甚至直接被清理掉。所以,一般來(lái)說(shuō),我并不建議,把應(yīng)用程序的性能優(yōu)化完全建立在系統(tǒng)緩存上。還是那句話,最好能在應(yīng)用程序的內(nèi)部分配內(nèi)存,構(gòu)建完全自主控制的緩存,比如 MySQL 的 InnoDB 引擎,就同時(shí)緩存了索引和數(shù)據(jù);或者,可以使用第三方的緩存應(yīng)用,比如 Memcached、Redis 等。總結(jié)
以上是生活随笔為你收集整理的32 | 答疑(四):阻塞、非阻塞 I/O 与同步、异步 I/O 的区别和联系的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 31 | 套路篇:磁盘 I/O 性能优化
- 下一篇: 02丨基础篇:到底应该怎么理解“平均负载