创建异步包装器的方法

时间:2014-11-03 15:10:43

标签: c# .net async-await c#-5.0

为同步方法创建异步包装器有多好?

// sync method
public void LongOperation()
{
    //code...
}


// versions of wrapper
public async Task LongOpertionWrapperAsyncV1()
{
    var task = Task.Factory.StartNew(LongOperation);
    await task.ConfigureAwait(false);
}

public Task LongOpertionWrapperAsyncV2()
{
    var task = Task.Factory.StartNew(LongOperation);
    task.ConfigureAwait(false);
    return task;
}

尽管两种版本的使用并不相同。

async Task Executor()
{
    await LongOpertionWrapperAsyncV1();
    await LongOpertionWrapperAsyncV2();
}

对于返回值的方法(Task< T>),我使用第一个版本。

但我想知道你的意见。

这些版本之间存在一般差异吗?

2 个答案:

答案 0 :(得分:15)

Neither solution is correct。最好的答案是公开同步代码的异步方法。我更多地了解"为什么" on my blog

如果您的代码是异步的,请使用asyncawait。如果不是,那就不要了。它应该由调用者决定如何调用代码(例如,使用Task.Run)。

答案 1 :(得分:6)

你应该使用"类似" V2:

public Task LongOpertionWrapperAsyncV2()
{
    return Task.Run(LongOperation);
}

async Task Executor()
{
    await LongOpertionWrapperAsyncV2().ConfigureAwait(false);
}

与V1相比,这可以节省一个上下文切换。只要你不需要等待另一个操作" async-Task是方法中的最后一个操作,你只需返回任务而不是等待它,并将await留给调用者(也可以或不能添加ConfigureAwait)。

Task.Factory.StartNew仅在您想提供HPT建议的TaskCreationOptions.LongRunning时才有必要。

<强>更新
正如斯蒂芬已经提到过的那样:在极少数情况下你应该做async over sync(但有)。因此,在实现这样的事情之前,请考虑一下你正在做什么。 Simplified说:如果它是CPU限制的工作,请不要这样做,如果它是某种&#34;等待IO&#34;可能会这样做。
我们在这里有一个案例,我们在这里开发了一个几乎同步的#34;库,用于控制不同的硬件设备。那里有整个&#34;通用库&#34;是异步的,但是一些低级设备驱动程序和/或访问库不支持async所以在最低级别我们执行以下操作:

public Task<byte[]> ReadAsync(int length)
{
    return Task.Run(() => hwDevice.Read(length));
}

hwDevice.Read仍然会锁定线程,但不会锁定CPU,因此在我们等待IO的过程中,UI会响应(在#34;真实直播中#34;这也是一些取消和错误处理逻辑)。