非同期 JSON-RPC プロトコルを使用するアプリケーションのネットワーク層を実装しています。
サーバーと通信するために、適切なリクエストを送信し、サーバーが応答を送信するまで待って、それを返すメソッドを作成したいと思います。async/await キーワードを使用するすべて。
簡単なサンプル コードを次に示します。
文字列応答;
Task<string> SendRequest(string methodName, string methodParams)
{
string request = generateRequest(methodName, methodParams);
await Send(request); // this will send using DataWriter, and StreamSocket
// block Task until response arrives
return response;
}
async void ReceiveLoop()
{
while (true)
{
uint numStrBytes = await _reader.LoadAsync(BufferSize);
string msg = _reader.ReadString(numStrBytes);
response = msg;
// unblock previously blocked SendRequest
}
}
}
async void main()
{
RecieveLoop();
}
async void SendButtonPressed()
{
string response = await SendRequest("Test method", "Test params");
Debug.WriteLine("Response = " + response);
}
このパターンの主な問題は、このブロッキング アクションです。このアクションは、現在のタスクをブロックし、タイムアウトを処理できるようにする必要があります。これを処理するために ManualResetEvent と WaitOne(int) を使用しようとしましたが、スレッド全体がフリーズし、async/await のみを使用しているため、アプリケーション全体がフリーズします (より正確には UI スレッド)。
私にとって非常にハックに見える解決策は、CancellationTokens で Task.Delay を使用できることです。
次のようになります。
...
CancellationTokenSource cts;
int timeout = 10000;
Task<string> SendRequest(string methodName, string methodParams)
{
... (prepare request, and send)
cts = new CancellationTokenSource();
try
{
await Task.Delay(timeout, cts.Token);
} catch(TaskCanceledException)
{
}
// do rest
}
async void ReceiveLoop()
{
// init recieve loop, and recieve message
cts.Cancel();
}
そのソリューションの問題(ハックのように見えることに加えて)はパフォーマンスです-すべてのリクエストで例外がスローされ、処理する必要があります(その場合はスキップされます)。これは遅くて痛いです:)
どうすればよりエレガントな方法でそれを行うことができますか? タスクをブロックする他のオプションはありますか?