创建异步包装器的方法

iwe*_*daz 6 .net c# 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;
}
Run Code Online (Sandbox Code Playgroud)

虽然两个版本的使用没有区别.

async Task Executor()
{
    await LongOpertionWrapperAsyncV1();
    await LongOpertionWrapperAsyncV2();
}
Run Code Online (Sandbox Code Playgroud)

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

但我想知道你的意见.

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

Ste*_*ary 15

两种解决方案都不正确.最好的答案是公开同步代码的异步方法.我在博客上更多地了解"为什么" .

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


Chr*_*Fin 6

你应该使用"像V2这样的东西:

public Task LongOpertionWrapperAsyncV2()
{
    return Task.Run(LongOperation);
}
Run Code Online (Sandbox Code Playgroud)

async Task Executor()
{
    await LongOpertionWrapperAsyncV2().ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)

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

Task.Factory.StartNew仅在您想提供TaskCreationOptions.LongRunningHPT建议时才需要.

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

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

hwDevice.Read确实还锁的线程,而不是CPU,所以UI在这段时间里,我们都在等待IO响应("实时直播"的也有一些取消和错误处理它周围的逻辑).