https://docs.legato.io/latest/apiFilesC.html#apiFilesC_asyncServer
https://docs.legato.io/latest/defFilesCdef.html#defFilesCdef_providesApiAsync
Legato 預設上,提供 API 的 server 端是同步的 server,也就是 client 端呼叫了 API,server 端會依序處理其接收到的 client 端的 API 請求。
若 API 的執行會花很多時間,且要 return 執行的結果給 client 端,這樣會花很多時間。
倘若將 server 端設定成非同步,則當 server 的 main thread 每接收到 client 端的一個 API 請求,我們就可以把這個 API 請求轉給 worker thread 執行,待 worker thread 完成後,再通知 main thread,main thread 再把執行結果回傳給 client 端。
這樣當 worker thread 在執行 API 時,main thread 可以繼續接收其他 client 端的 API 請求、並再轉發給其他 worker thread 處理,而不會被卡住。
下圖是簡單的示意圖,有兩個 client,分別是 client1 和 client2。client1 先呼叫 API1,之後 client2 才呼叫 API2,而 API1 的執行時間會比 API2 的執行時間長許多。
若是 sync server,client2 的 API2 請求必須等到 client1 的 API1 請求做完,才會執行 API2;但若是 async server 的話,client2 很快就可以得到 API2 執行的結果。
PS. 使用 async server 的話,client 端呼叫 API 後仍會卡在那邊直到該 API return 喔。
https://docs.legato.io/latest/apiFilesC.html#apiFilesC_asyncServer
There are two alternatives to implement the server-side functionality.
The default case is where each server-side function has the same interface as the client-side function. The server-side function takes the IN
parameters, and returns the OUT
parameters and function result when the function exits.
In the async-server case, the server-side function doesn't necessarily return the OUT
parameters and function result when it exits. Instead, there's a separate Respond
function for each server-side function. The OUT
parameters and function result are returned by passing these values to the Respond
function. The Respond
function can be called at any time, normally after the server-side function has exited.
Regardless of how the server-side functions are implemented, the client-side function waits until the OUT
parameters and function result are returned.
無論 server 端是用哪種方式實作,client 端都會等到 OUT
參數或 function return
The async-server functionality is not enabled by default. Enable it by using the .cdef
provides [async]
.
https://docs.legato.io/latest/defFilesCdef.html#defFilesCdef_providesApiAsync
The server of a service can also implement the functions as if they were called directly by the client (even though the client may be running inside another process). When the client calls an API function, the server's API function gets called, and when the server returns from the function, the function returns in the client process.
Sometimes the server needs to hold onto the client request and do other things (like handing requests from other clients in the meantime) before sending a response back. This is called asynchronous mode, and is enabled using the [async]
keyword on the end of the api
section entry:
When asynchronous mode is enabled for a server-side interface, the generated code changes as follows:
commandRef
parameter is added to the beginning of all the API functions' parameter lists.Respond()
function is generated for every API function.In async mode, the server responds to the client's call to API function F()
by calling the associated FRespond()
function.
The Respond
functions all take the commandRef
as their first parameter. If an API function has a return value, that return value is sent to the client through the second parameter of the Respond
function. Any output parameters defined in the API function are also passed as parameters to the Respond
function.
See API Files for more information, or try it and have a look at the generated header files.
若我們想將某個 .api
設定成非同步,則需要在 server 的 Component.cdef
的 provides
section 的 api
section 將該 API 標記成 [async]
,如下:
[async]
的效果接下來來看將 API 標示成 [async]
後,對其所產生的 C 語言的 function prototype 會有什麼變化~
假設 .api
裡面定義了以下兩個 API 的 interface:
function_a
有三個參數,a
和 b
都是 IN
參數,result
則是 OUT
參數(也就是 result
是 pass by address 的方式傳到 function 內,並在 function 內修改 result
的值),然後 return void
。
function_b
則有兩個參數,in_parameter
是 IN
參數,out_parameter
則是 OUT
參數,最後還會 return 一個 int_32
。
若沒設定為非同步 server 的話,預期在 C 語言的 function prototype 會是如下:
但使用 [async]
後,function prototype 會有所變動。
執行完 mkapp -t simulation yourApp.adef
後,查看 _build_yourApp/simulation/api/5362441aefbd3b1670a884ba65439c29/async_server/<interface>_server.h
(以下僅節錄部份):
可以看到實際的 function prototype 有了以下的變化:
function_b
原本設定 return int32
,但全部的 function 都變成 return void
。Respond
function,像是 function_a
就多出了 function_aRespond
,function_b
就多出了 function_bRespond
。
Respond
function。Respond
function 的第二個參數,後面則依序是被設定為 OUT
的參數。<interface>_ServerCmdRef_t _cmdRef
所以 sync
server 跟 async
server 最大的差別在於:async
server 的 API 是透過呼叫 Respond
function 來 return,代表我們可以把事情丟給一個 worker thread 來專門處理這個 API 的事情,等到 worker thread 做完之後,再呼叫 Respond
function 來 return。
PS. 但是要注意的是 Respond
function 只能由 main thread 呼叫,不可由 worker thread 呼叫,否則執行時會出現錯誤訊息:
所以我們可以讓 worker thread 做完事情後發出 event,然後 main thread 執行這個 event 的 handler,並且在該 handler 裡面呼叫該 API 的 Respond
function。
sync
server 如果沒有要 return 的話,應該也是可以丟給 worker thread 處理事情;但如果要 return 的話,main thread 基本上就一定要等待 worker thread 做完事情(像是使用 le_thread_Join
等 API),才能取得 worker thread 的結果,最後才 return。這樣 main thread 仍會被卡在那邊,沒辦法趁 worker thread 在做事的時候先去做其他事。
以下此例子,server 提供兩個 API,function_a
和 function_b
:
function_a
會睡 10 秒。function_b
不會睡覺。client1
先呼叫 function_a
,然後 client2
才呼叫 function_b
。
在 sync
server 的狀況,由於 client1
先呼叫了 function_a
,所以一定會睡完 10 秒,結束後才會執行 function_b
。
在 async
server,把 function_a
睡十秒的事情丟到 worker thread 裡面處理,所以 worker thread 睡 10 秒。把事情丟給 worker thread 後,main thread 就可以繼續做事,當 main thread 接收到 client2
使用 function_b
的請求,main thread 就把事情丟給專門處理 function_b
的 worker thread。所以預期 client2
可以先得到結果,client1
則必須等 10 秒才能得到結果。
asyncServer/asyncServerApp.adef
asyncServer/server_api.api
asyncServer/asyncServerComp/server.c
asyncServer/asyncServerComp/Component.cdef
client1/asyncServer_client1App.adef
client1/client1Comp/client1.c
client1/client1Comp/Component.cdef
client2/asyncServer_client2App.adef
client2/client2Comp/client2.c
client2/client2Comp/Component.cdef
以下僅列出重要的 log: