正确制作异步方法

时间:2017-12-11 07:45:36

标签: c# asynchronous task task-parallel-library

我google了很多,目前我发现的唯一异步实现(包括MSDN网站)如下:

public async void Foo()
{
...
 await StreamReader.ReadAsync();
...
}

所以在所有情况下,他们都使用一些已经异步的方法。这不是我需要的。

让我们说我的方法很重要:

public void DoSomthing()
{
...
}

有一种方法可以称之为DoSomething:

public void MajorMethod()
{
  DoSomething();
}

我想让DoSomething ayncthonous并将其称为。<​​/ p>

我看到的唯一解决方案是:

public Task MajorMethod()
{
  return Task.Run(()=>DoSomething());
}

但是我读到一些评论说它并不是真正的异步。那么如何让DoSomething异步?

2 个答案:

答案 0 :(得分:0)

如果MajorMethod除了调用DoSomething之外别无其他事情,那么您的代码就可以了。 但是,如果您在致电DoSomething后需要执行其他操作,请将MajorMethod标记为async,并在await之前使用Task.Run

public async Task MajorMethod()
{
    await Task.Run(()=>DoSomething());

    //stuff in here will executed after DoSomething completed
}

来自MSDN的示例:Asynchronous programming

或只是google c# async

答案 1 :(得分:0)

您应该清楚Task Asynchronous Pattern中的async / await play角色。制作异步方法不会像这样异步地执行操作。标记现有方法async不会神奇地异步执行其中的所有内容。它的主要作用是,现在你可以在方法中使用await(我读过,如果async关键字是必要的,它甚至会被讨论;它被添加以避免在现有方法中的局部变量将命名为await)。

await本身也不提供异步,它提供了一种同步到另一个异步方法并在另一个操作仍在运行时产生的方法。您可以await另一个async方法,但除非在链中有一个实际的Task在另一个线程中运行,否则异步方法甚至可以同步返回。

因此,这意味着您需要一个异步运行 first 的操作(例如数据库查询,文件访问,网络通信),然后从那里创建一系列async方法await之前的方法。

现在,在您的情况下,当您有一个不等待外部资源的计算密集型方法时,您可以选择异步执行操作。由于现代CPU通常可以使用多个核心,因此可以提高性能和应用程序响应速度。该方法不是async,因为它不等待任何事情:

void DoSomething()
{
    //...
}

Task DoSomethingAsync() {
    return Task.Run(DoSomething);
}

DoSomethingAsync的所有呼叫者现在可以使用await与在后台运行的此操作同步(请注意返回类型更改为Task以允许呼叫者等待):

async Task MajorMethod() {
    //...
    await DoSomethingAsync();
    //...
}

这将允许MajorMethod来电者与之同步。您还可以做的是在MajorMethod正在运行时执行DoSomethingAsync中的内容(并且仍然等待允许调用者执行更多并行操作):

async Task MajorMethod() {
    //This part will run before DoSomethingAsync
    //...
    Task doSomethingTask = DoSomethingAsync();
    //This part is executed at the same time as DoSomethingAsync
    //...
    await doSomethingTask; //Here the caller can do more operations while DoSomething is running
    //This part will be executed after DoSomethingAsync has finished
    //...
}

这种获取任务,执行某些操作然后等待任务的形式必须在链中的某处完成,否则您无法从异步操作中获益。即使这可能是过度概括,因为同步可以以更微妙的方式发生,例如使用自定义同步上下文。但就你的问题而言,你应该选择:在一端有一个实际的任务,在异步调用之后但在等待另一端之前完成的事情。