我目前正在开发一个需要通过网络控制收集设备的服务器应用程序。正因为如此,我们需要做很多并行编程。随着时间的推移,我了解到处理实体(线程/进程/应用程序)之间的通信有三种方法。遗憾的是,这三种方法都有其缺点。
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
第三种解决方案的问题是您不能从调用者的函数返回。如果您想要在两者之间做的工作与您异步完成的工作完全无关,这将使其不合适。很长一段时间以来,我想知道是否还有其他异步调用函数的可能性,一种没有上面列出的选项的缺点。有没有人有一个想法,也许是一些聪明的把戏?
注意:给出的示例是类 C++ 的伪代码。但是,我认为这个问题同样适用于 C# 和 Java,可能还有很多其他语言。