我不确定我是否可以在这里解释一下,但让我试一试。下面的代码只是为了显示这个想法,因为我只是在这里输入它而不验证编译器中的所有内容。
我有一个方法(比如说Method1)我在做两件事。 1.调用Web服务方法来执行操作。 2.之后,我在同一个Web服务对象上进行轮询,等待操作结果可用。
所以基本上如下所示。
public class MyClass
{
Method1()
{
// call Web service method
// code for polling
}
}
然而,这种方法使得Method1阻塞,直到在轮询期间确定的动作结果可用。我想更改它,以便Method1的调用者可以在调用Web服务方法后立即返回,并且可以在Web服务结果可用后以某种方式发出信号。所以我想将AutoResetEvent对象作为类成员,我在轮询期间设置为信号状态。
public class MyClass
{
public AutoResetEvent autoEvent = new AutoResetEvent(false);
Method1()
{
// call Web service method
}
Method2()
{
// code for polling
// change state of autoEvent to signaled once results are availble
}
}
使用这种方法,此API的用户只需调用立即返回的Method1,他们就可以等待autoEvent发出信号。问题是谁会在这种情况下调用Method2?
答案 0 :(得分:1)
有几种不同的异步代码方法。今天.NET中最常见的是使用Tasks。对于一个基本示例,您可以执行以下操作:
Task task = Task.Run(() => DoSomething());
task.ContinueWith(() => DoAfterSomething());
这允许代码在后台线程上执行任务时继续处理。这可能看起来有点罗嗦和clumbsy与所有lambda和子方法,这就是为什么引入了async \ await模式。这看起来像:
Task<int> DoSomethingAsync()
{
// do something asynchronously..
}
async Task<int> ExampleAsync()
{
int result = await DoSomethingAsync();
DoAfterSomething();
return 42;
}
请注意,可以在与原始调用者不同的线程上调用DoAfterSomething。
常用的另一种方法是APM方法。这包括两个启动异步线程的方法和另一个完成它的方法(通常是BeginX和EndX)。这通常看起来像:
FileStream fStream = /* etc */
byte[] buffer = /* etc */
void ReadFile(FileStream fStream)
{
var asyncResult = fStream.BeginRead(buffer, 0 , buffer.Length, new AsyncCallback(EndReadCallback), null);
}
void EndReadCallback(IAsyncResult result)
{
int length = fStream.EndRead(result);
// continue processing on buffer
}
另一种方法是EAP模型,它使用事件来触发完成。这个模型在.NET框架中并没有被广泛使用,但它就在那里。使用类似的东西:
WebDownload download = /* etc */
download.DownloadComplete += (buffer) => { /* do something with buffer */ };
download.Get("http://foo/img.jpg");
就个人而言,我使用async \ await来创建我创建的所有内容,但是如果您在遗留组件中遇到它们,其他方法也很有用。如果您需要将APM或EAP转换为基于任务,您可以使用Task.Factory.FromAsync或使用TaskCompletionSource
轻松完成此操作