我正在学习C# Asnc-等待模式,目前正在阅读C#烹饪书中的并发性。
他讨论了用TaskCompletionSource (TCS)将旧的非TAP异步模式包装到TAP结构中。我不明白的是,为什么他只返回TCS对象的Task属性而不是等待它TCS.Task?
下面是示例代码:
旧的包装方法是DownloadString(.):
public interface IMyAsyncHttpService
{
void DownloadString(Uri address, Action<string, Exception> callback);
}将其封装到TAP结构中:
public static Task<string> DownloadStringAsync(
this IMyAsyncHttpService httpService, Uri address)
{
var tcs = new TaskCompletionSource<string>();
httpService.DownloadString(address, (result, exception) =>
{
if (exception != null)
tcs.TrySetException(exception);
else
tcs.TrySetResult(result);
});
return tcs.Task;
}现在为什么不这样做呢:
public static async Task<string> DownloadStringAsync(
this IMyAsyncHttpService httpService, Uri address)
{
var tcs = new TaskCompletionSource<string>();
httpService.DownloadString(address, (result, exception) =>
{
if (exception != null)
tcs.TrySetException(exception);
else
tcs.TrySetResult(result);
});
return await tcs.Task;
}两者之间有功能上的区别吗?第二个不是更自然吗?
发布于 2019-02-18 11:40:16
通过标记它异步,编译器将生成警告,认为它应该等待此方法。
您不必将自己的方法标记为async,以获得“任务未等待”警告。下面的代码为对T和U的调用生成相同的警告
static async Task Main(string[] args)
{
Console.WriteLine("Done");
T();
U();
Console.WriteLine("Hello");
}
public static Task T()
{
return Task.CompletedTask;
}
public static async Task U()
{
await Task.Yield();
return;
}每当您发现自己使用的方法只包含单个await,并且这是它所做的最后一件事(除了可能返回所期待的值)时,您应该问自己它正在添加什么值。除了异常处理上的一些差异之外,它只是在混合中添加了一个额外的Task。
await通常是一种表示“我现在没有有用的工作要做,但当这个其他的Task完成时”的方式,当然这不是真的(您以后没有其他的工作要做)。所以跳过await,只返回你所期待的东西。
发布于 2019-02-18 11:03:11
您的版本更加复杂--而不是仅仅返回任务,而是创建方法异步,等待您可能返回的任务。
发布于 2019-02-18 11:08:24
有一个微妙的实际差异(除了await运行速度较慢的版本外)。
在第一个示例中,如果DownloadString抛出一个异常(而不是调用委托,而是使用exception set传递它),那么该异常将通过对DownloadStringAsync的调用而出现气泡。
在第二个过程中,异常被打包到从Task返回的DownloadStringAsync中。
因此,假设DownloadString抛出此异常(并且没有发生其他异常):
Task<string> task;
try
{
task = httpService.DownloadStringAsync(...);
}
catch (Exception e)
{
// Catches the exception ONLY in your first non-async example
}
try
{
await task;
}
catch (Exception e)
{
// Catches the exception ONLY in your second async example
}你可能不在乎区别--如果你只写:
await httpService.DownloadStringAsync(...);你不会注意到区别的。
同样,只有当DownloadString方法本身抛出时才会发生这种情况。如果它调用您将exception设置为值的委托,那么两种情况之间没有明显的差别。
https://stackoverflow.com/questions/54745531
复制相似问题