1. 程式人生 > >ROS Service vs Topic

ROS Service vs Topic

這學期當TA了,改作業的時候service和topic這兩個一直比較模糊的問題又跳了出來,覺得這個坑還是得填上,那就留一篇部落格吧。

實驗速度

1. via topic

同一臺機器上通過topic傳輸資料用時(單位/s)

上圖是以前ROS課上做的一個實驗,內容是測試一個publisher和一個subscriber之間通訊所用的時間。兩個node都很簡單,publisher傳送一個字串,字串帶有標號;subscriber回顯該字串,字串長度不超過20個char。

怎麼去標定傳送時間是接收時間呢?目前使用的方法就是在publisher傳送前使用ROS_INFO輸出一個訊息,訊息會帶有ROS的時間戳;subscriber的callback函式裡邊也使用ROS_INFO輸出一個帶時間戳的訊息。雖然說這種方法並不是非常精準,但目前也沒有想到更好的辦法了,哪怕是使用header裡邊的time stamp也有一個獲得當前時間和賦值的過程,難以百分百精確,所以目前只能這樣粗略測量。

根據實驗資料可以發現在同一臺機器上,兩個node通過topic通訊,大致產生0.7ms的延遲。(本人機子i5-3210M/4G)

2. via service

同一臺機器上client call server後server接收到資料用時(單位/s)

這張圖是今天自己做的測試,可以看到平均時間大約在3ms左右。

測量的方法也是跟上面的類似。Client在call之前先輸出一個帶時間戳的訊息,server在接收到請求執行操作前也會輸出一個帶時間戳的訊息。這次client與server之間傳遞的訊息更短,是兩個int。

從上圖我們不難發現,通過service通訊居然比topic延遲要高?實在是不願意相信,因為這跟我一開始的理解是相違背的。為了控制實驗環境平臺的一致性(我從groovy換到了indigo),於是重做了以前的那個實驗,粗測通過topic傳輸的延遲時間,發現依然是0.7ms左右。

理論速度

為何前面的實驗結果讓我如此驚訝?

官方文件中寫明,client與server之間維持著一個持久連線。對於這種RPC請求/回覆機制,官方給出的評價是“面對低魯棒性的服務程式變更有著更好的效能表現”(higher performance at the cost of less robustness to service provider changes)1

說到持久連線,不禁讓人想起ROSTCP。照這麼說,如果在ROS架構下node之間通訊的底層實現都是通過ROSTCP/ROSUDP的話,那理應via service應該跟via topic的速度相當,如果將“永續性”納入考慮範圍的話,service甚至應該比topic更快一些才對。但實際情況是via service的時延是via topic的4倍左右。如此大的差距,實在讓人百思不得其解。

實現機制——同步與非同步

其實在開始寫這篇博文的時候,我都依然沒有想明白這個問題。邊寫邊查資料,看到ros answer上一位大大在描述這兩種機制時,用到了asynchronous和synchronous這兩個字眼2。回到宿舍一邊洗著冷水澡一邊在想,忽然靈光一現!是的,實驗的結果是沒有問題的,有問題的是我的實驗方法!

- Asynchronous Topic

Topic是非同步的。簡簡單單的一句話,裡邊卻隱含了千言萬語。讓我關注起這一點的原因除了ros answer上面的那篇問答,還有一個就是自己做的另一個實驗:建立一個publisher,pub的速度是100Hz,傳送緩衝區的大小隻有1;建立一個subscriber,呼叫callback函式的的速度是1Hz(用spinOnce),但接收緩衝區的大小是1000。這樣的效果就是,publisher近乎勻速地傳送著資料,每秒100次;而subscriber每一秒呼叫一次callback函式(spinOnce),每次呼叫都一次性地處理接收緩衝區內的所有資料。由於接收緩衝區大小遠大於傳送頻率,所以接收緩衝區不存在滿的情況,所以就能看到subscriber每秒都會很快地處理完100條訊息,然後進入休眠,再被喚醒執行callback,再休眠……

而之前用於測試的subscriber,我使用的是spin。這也就意味著,回撥函式一直是處於類似於忙等待的狀態的,一旦發現接收緩衝區內有資料,即刻取出作運算(前提當然是獲得CPU分片時間)。這也就說明了為什麼實驗得出的結果via topic會更快!但要注意了,忙等待是會佔用硬體資源的。在這種簡單的實驗條件下,via topic固然是很快,但當一個大專案跑起來時,它之前的高效能表現可能要大打折扣。

- Synchronous Service

至於server,在基於RPC請求/回覆機制的前提下,它在接收到呼叫請求前都是處於休眠狀態的。Client的call請求將server喚醒,然後server執行請求,再返回結果給client。所以之前在計時的時候,大部分的時間都是消耗在將server從休眠狀態喚醒上了!所以才會看起來比via topic慢。

分析到這裡,我就在想,那真正的client與server之間通訊的時延,是不是可以利用server返回結果給client這段時間算出呢?這才是真正拋開了將server從休眠喚醒的時間影響,是client與server通訊的真正時延!於是又有了下圖:
同一臺機器上server返回結果後client接收到資料用時(單位/s)

果不其然!表中資料的中位數應該在0.3ms左右,也就是說,從server返回結果到client接收到結果,只需要0.3ms的時間!儘管使用spin通過topic轉發資料類似於忙等待(也許ROS的內部機制會對spin的頻率作最高限制),但也需要大約0.7ms的時間!而service機制中,client發出call請求之後就會進入阻塞狀態,直至server返回結果,期間的時延是via topic的一半而已!

而從這個資料我們還可以估計出將休眠狀態的server喚醒,所需要的時間大約是2.7ms。如果計算一來一回,client從發出call請求到接收返回結果,除去請求被執行的時間,在通訊上耗費的時間約是3.3ms,其中將server喚醒的時間約佔82%!

- Conclusion

Topic與Service各有優劣。在設計專案的時候,要周全考慮各個方面的因素。Service比較適合用於執行復雜的、排程次數較低的任務。而topic則適合在通訊頻率高的情況下使用。再者,使用ros::Rate和sleep合理設定程式的執行速率,能使程式彈性更大,增強可維護性。使用topic時,也別忘了關注一下緩衝區的大小設定。

優劣分析

Service

- 優點:

  • Client只需要關注發出命令請求、接收反饋,而無須關注底層實現,系統可維護性高
  • Client維護著一個與server的持久連線(persistent connection),在單純的資料傳輸上可以做到更快,尤其是在分散式作業時

- 缺點:

  • 當server單方改變執行模式或者存在bug的時候,client無法得知具體情況,因為server程式對client而言是透明的。在這種情況下,client只能得到一個錯誤的資料,或者被告知執行失敗,甚至是等待超時
  • Server喚醒耗時太大,不建議用於通訊頻率高的情況

Topic

- 優點:

  • 能非常方便地通過監聽topic的方法檢視各個node的執行狀態等資訊,可維護性高
  • 能根據實際情況調整發送速率、傳送/接收緩衝區大小,使之適應專案需求
  • Topic是多對多的,可操作性強;而service只能一對多(一個server應對多個client)

- 缺點:

  • 因為是非同步架構,回撥函式的執行頻率設計對系統整體效能影響很大
  • 對於使用頻率不高的程式,若使用topic進行資訊交換,想要減少額外系統開銷的辦法就是降低迴調的速率。但一旦降低迴調的速率,同時受到負面影響的還有系統的實時性