任务API感觉有点像失败,考虑到我可以用它做的每件事情都有更多 DON' T 而不是 DO 。但是我试图更多地使用它,我对async void
的整个问题感到困惑。
我的问题发生在我的应用程序永远使用本地数据文件的地方,并且因为它使用了快速同步调用。现在一些远程源是一个选项,它们有足够的延迟我将它们全部切换为异步。
所以我有一个方法可能看起来像这样:
void InitializeData() {
SomeProperty = _dataSource.Load(...);
}
我想为低摩擦做的天真的事情是:
Task InitializeDataAsync() {
return Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
但是有很多关于使用async void
是多么可怕的文章,并且他们似乎在讨论返回任务时模糊不清。因此,我最好的选择是:
Task<DataType> FetchDataAsync() {
return _dataSource.LoadAsync(...);
}
...然后追捕所有来电者并让他们遵守?
我觉得人们提出的论点是async void
是不好的,因为async Task
的不同行为和使用await
时可怕的UnobservedTaskException。在这种情况下,我不太可能使用await
。或者,如果我确实使用await,它总是会有一个try / catch,因为我们已经对UnobservedTaskException产生了偏执。
所以:
async void
&#34;和#34;不要使用Task
?await
,是否会减轻这种影响?await
,总是用try / catch包装它可以缓解这个问题吗? 答案 0 :(得分:9)
async void
与返回Task
不同。 async void
的问题是无法观察任务异常(除了全局异常处理程序之外),也无法等待任务完成(实际上你不能await
async void
方法,因为await
没有任何内容,因此应该避免这种情况。
返回Task
没有这些问题,如果你知道它完成时await
,你会得到例外,等待返回Task
完全可以接受。
答案 1 :(得分:2)
看起来你只是感到困惑。 await / async API非常简单。唯一令人困惑的部分是理解the difference between await/async API and the Task API。我不会详细了解这一点,因为Stephen Cleary的博客清楚地涵盖了这一点,但这里有重要的摘录:
要重申我上一篇文章中的一句话,请使用Task.Run调用CPU绑定方法(来自GUI线程)。不要仅仅使用它来“为我的异步方法提供可供使用的东西”。
...下
我想为低摩擦做的天真的事情是:
Task InitializeDataAsync() {
return Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
这是将Sync代码卸载到Async包装器中的一个明显案例,它实际上没有任何好处。
但是有很多关于使用async void有多糟糕的文章,
这显然是不 async void
方法。这是一种非异步Task
返回方法。这是一个异步void方法:
async void InitializeDataAsync() {
await Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
他们似乎在讨论返回任务时模糊不清。
我没有看到任何模糊这些信息的内容。这很简单;如果您使用async
方法,请始终返回Task
或Task<T>
(除非如下所述)。使用这两个(Task
或Task<T>
)之间的区别纯粹是设计/架构。
所以我最好的选择就是:
Best在这里真的是一个意见。这两项都有效,并且不要忘记 async/wait
async Task<DataType> FetchDataAsync() {
return await _dataSource.LoadAsync(...);
}
async Task FetchDataAsync() {
_data = await _dataSource.LoadAsync(...);
}
我觉得人们提出的论点是async void很糟糕,因为async Task的行为不同,而且当你使用await时可怕的UnobservedTaskException。
The most important difference is how exceptions are handled:
摘录:
Async void方法具有不同的错误处理语义。当异步任务或异步任务方法抛出异常时,将捕获该异常并将其放在Task对象上。使用async void方法时,没有Task对象,因此异步void方法抛出的任何异常都将直接在async void方法启动时处于活动状态的SynchronizationContext上引发。
所以
或者,如果我确实使用await,它总是会有一个try / catch,因为我们已经对UnobservedTaskException产生了偏执。
这意味着您无法通过try / catch绕过异步void来捕获异常。这是个大问题!
是不是&#34;不要使用async void&#34;和#34;不要使用任务?&#34;
这是苹果和橘子。是的:除非您将async void
用于async event handlers,否则请勿使用 String a = "545F6 6 100";
String b = "12N45 A 50";
List<String> results = new ArrayList<>(); // here you will store matching numbers
for(String str : a.split("\\s+")) { // for each String that you get after splitting source String at whitespace characters...
if(str.matches("\\b[\\d]+\\b")) { //check if that String matches given pattern: word boundary-only digits-word boundary
results.add(str); // it there is a match, add this String to results ArrayList
} else {
System.out.println("The number " + str + " is invalid");
}
}
System.out.println("Valid numbers: " + Arrays.toString(results.toArray())); // just to print results
results.clear();
System.out.println();
for(String str : b.split("\\s+")) {
if(str.matches("\\b[\\d]+\\b")) {
results.add(str);
} else {
System.out.println("The number " + str + " is invalid");
}
}
System.out.println("Valid numbers: " + Arrays.toString(results.toArray()));
。
不要使用任务,除非他们受CPU限制或您正在使用框架调用(或者您已正确包装自己使用IO Completion Ports的方法)。
如果你没有使用await,它会减轻吗?
希望现在您了解await / async与Task不同,您尝试做的是编写所有等待/异步代码。
如果你确实使用了await,那么总是用try / catch包装它可以缓解这个问题吗?
取决于上述情况。