私は現在、ネットワーク経由で収集デバイスを制御する必要があるサーバー アプリケーションに取り組んでいます。このため、多くの並列プログラミングを行う必要があります。時間の経過とともに、処理エンティティ (スレッド/プロセス/アプリケーション) 間の通信には 3 つのアプローチがあることを学びました。残念ながら、3 つのアプローチにはそれぞれ欠点があります。
A)同期リクエスト(同期関数呼び出し)を行うことができます。この場合、呼び出し元は、関数が処理されて応答が受信されるまで待機します。例えば:
const bool convertedSuccessfully = Sync_ConvertMovie(params);
問題は、発信者がアイドリングしていることです。時々、これはオプションではありません。たとえば、呼び出しがユーザー インターフェイス スレッドによって行われた場合、応答が到着するまでアプリケーションがブロックされているように見えますが、これには長い時間がかかる可能性があります。
B)非同期リクエストを作成し、コールバックが行われるのを待つことができます。クライアントコードは、実行する必要があるものは何でも続行できます。
Async_ConvertMovie(params, TheFunctionToCallWhenTheResponseArrives);
このソリューションには、コールバック関数が必然的に別のスレッドで実行されるという大きな欠点があります。問題は、発信者に応答を返すのが難しいことです。たとえば、サービスを非同期的に呼び出したダイアログのボタンをクリックしましたが、コールバックが到着したときにダイアログが長時間閉じられていました。
void TheFunctionToCallWhenTheResponseArrives()
{
//Difficulty 1: how to get to the dialog instance?
//Difficulty 2: how to guarantee in a thread-safe manner that
// the dialog instance is still valid?
}
これ自体はそれほど大きな問題ではありません。ただし、そのような呼び出しを複数回行いたい場合、それらはすべて前の呼び出しの応答に依存します。私の経験では、これは手に負えないほど複雑になります。
C)最後のオプションは、非同期リクエストを作成し、レスポンスが到着するまでポーリングを続けることです。has-the-response-arrived-yet チェックの合間に、何か役に立つことができます。これは、実行する一連の非同期関数呼び出しがある場合を解決するために、私が知っている最善の解決策です。これは、応答が到着したときに呼び出し元のコンテキスト全体がまだ残っているという大きな利点があるためです。また、呼び出しの論理的な順序はかなり明確なままです。例えば:
const CallHandle c1 = Sync_ConvertMovie(sourceFile, destFile);
while(!c1.ResponseHasArrived())
{
//... do something in the meanwhile
}
if (!c1.IsSuccessful())
return;
const CallHandle c2 = Sync_CopyFile(destFile, otherLocation);
while(!c1.ResponseHasArrived())
{
//... do something in the meanwhile
}
if (c1.IsSuccessful())
//show a success dialog
この 3 番目の解決策の問題は、呼び出し元の関数から戻ることができないことです。これは、間にやりたい作業が非同期で行われている作業とはまったく関係がない場合には適していません。長い間、上記のオプションの欠点を持たない関数を非同期的に呼び出す可能性があるかどうか疑問に思っていました。誰かがアイデアを持っていますか、おそらく何か巧妙なトリックはありますか?
注:例は C++ ライクな擬似コードです。ただし、この質問は C# と Java、そしておそらく他の多くの言語にも同様に当てはまると思います。