一、線程和分布式的通信
隨著技術的不斷發展,多線程和分布式通信愈發的普及。那么在這種場景下的如何進行數據的通信,便成為了一個非常典型的問題。無論是多線程還是分布式,其實其抽象出來的通信機制都是類似的。或者說換句話,多線程和分布式被普及的原因是一樣的,那就是如何解決大數據量的快速交互,即解決生產者和消費者的問題。
這種通信機制有很多種,在前面也分別的進行過闡述,比如常見的事件、管道、網絡、消息等等。這些通信機制,各有各的優點和適用場景,當然也存在著各種各樣的問題和缺點。這就需要開發者能夠靈活的綜合運用這些技術來解決問題。
二、生產者和消費者的平衡
回到最常見的生產者消費者的問題,即生產隊列和消費隊列的最優的動態平衡。生產者的線程和消費者的線程要匹配,既不能生產的過多,導致消費隊列的積壓甚至因此而崩潰,也不能因為生產者的產出太少,導致消費者隊列的等待。
一般在這種情況下,可能很多開發者會選擇使用線程同步來解決問題,也可能會使用一些消息框架來解決這類問題。可同步帶來的性能損失,如何降低到最低?那如果使用無鎖編程呢?會不會帶來效率的顯著提升?
三、問題和解決
從上面的分析可以判斷出,其實無論哪種方式,都需要處理同步的粒度的問題。舉一個簡單的例子,一個生產者和一個消費者,生產者在把消息壓入隊列后就進行一個同步的通知(不管是使用事件還是條件變量等),還是等到某種條件下再進行同步通知效率更高呢?也就是說,不用每次生產后都進行通知,而在某種情況下才會通知。由于同步事件的通知會導致線程的切換和上下文的處理,所以基本上可以判定,后者會更優。但優多少需要實際的場景進行驗證。只是從理論上看,這種情況是占有優勢的。
在無鎖隊列中,如果生產者速度比較慢,消費者比較快,CAS的原理是占用CPU進行自旋等待,那設計上肯定不能讓消費者沒事總那兒旋轉占用著CPU,一般會有一個機制在多長時間后進行等待機制讓出CPU。或者在突傳情況下,CAS自旋就非常有意義,但在突傳過后,CAS一定要讓出CPU。所以就可以基本得出一個結論,在消費者讓出CPU休眠時,再進行同步通知進行喚醒,此時的效果肯定是最佳的。
這種機制不光是推理出來,在實踐中也是如此,比如使用一些開源框架中即是進行這樣設計的。一些開源的無鎖隊列,經過測試發現,連續通知和休眠后通知,其實效率還是差不少的。這也是一個非常明顯的例證。
那么如何進行線程間狀態的判斷呢?這個有很多種方法,一般來說可以設置一個雙方都需要讀寫操作的變量,而CAS正是擅長對這種固定值的判斷的,通過固定值與隊列間的某種特定的條件,即可判斷互相的狀態。
四、總結
其實隊列的處理,不光有這種細節需要處理,包括內存大小的處理,是否提前處理,都是需要考慮的。正如前面所說,一個隊列的設計,不僅僅是一個算法的問題,可能涉及到很多的技術知識和相關的難點。如何能夠綜合運用這些知識適配開發場景,就是對設計師的一個考驗了。