摆脱阻止代码

时间:2014-10-01 02:58:04

标签: .net c#-4.0 blocking autoresetevent

我不确定我是否可以在这里解释一下,但让我试一试。下面的代码只是为了显示这个想法,因为我只是在这里输入它而不验证编译器中的所有内容。

我有一个方法(比如说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?

1 个答案:

答案 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

轻松完成此操作