我有一个WCF操作Say Service1.OperationA。此操作必须调用另一个Operartion Service2.OprationB。 OperationB被称为OperationA中的最后一步。 OperationB只返回true或false。
操作B会对数据库执行一些读写操作,这可能需要很长时间。从操作B调用此方法时,我不想等待OperationB的结果。即使抛出异常,我也会捕获并记录异常。还有其他操作,如OperationC,可能要等待OperationB的结果。
答案 0 :(得分:2)
最简单的方法是使用async-await。
<TResult
&gt; 在异步函数中,只需调用另一个异步函数即可。如果您需要结果,请立即使用await,如果您还有其他事情要做,请在执行异步功能时执行此操作,并在需要结果时等待任务。
让我们假设你的慢速OperationB下载完整的莎士比亚。作为异步函数,这将是:
private async Task<string> OparationBAsync()
{ // read Shakespeare sonnets:
string uri = "http://www.gutenberg.org/cache/epub/1041/pg1041.txt";
using (var webClient = new WebClient())
{
return await webClient.DownloadStringTaskAsync(uri);
}
}
如果OperationA是异步的并且您想等待OperationB的结果,则等待结果:
private async Task OperationAAsync(...)
{
Task<string> taskReadBook = OperationB();
// while reading do some other useful stuff
// when you need the result: await for the task:
string book = await taskReadBook;
ProcessBook (book);
}
当然,如果您不需要结果,请不要等待它。调用另一个异步函数,并在准备好后返回。您可能会收到编译器警告,表示您没有等待,但这不是您想要的吗?
<TResult
&gt;
private async void Button1_Clicked(object sender, ...)
{
OperationA();
// use the synchronous version or
// use the async version and wait until finished:
await OperationAAsync();
OperationBAsync();
// do not await until finished.
}
问题是,如果你想对结果做一些事情,没有人会知道OperationBAsync已经完成。假设您有一个写入读取数据的operationCAsync:
private async Task OperationCAsync(string filename, string text)
{
using (var textWriter = new StreamWriter(fileName))
{
await WriteAsync(text);
}
}
最简单的方法是调用函数等待:
private async void Button1_Clicked(object sender, ...)
{
await OperationAAsync();
var book = await OperationBAsync();
await OperationC("mybook.txt", book);
}
即使您没有显式启动任务,异步也会使您的UI在等待函数期间保持响应。请注意,它仍然是执行处理的UI线程,因此在代码未等待时,您的UI线程将忙碌。如果你真的想从这个负担中释放UI,你需要启动一个单独的线程:
private void Button1_Clicked(object sender, ...)
{ // not async version, the UI will not wait for the result
Task.Run( () => Button1ClickedHandler();
}
private async Task Button1ClickedHandler()
{
await OperationA();
var book = await OperationB();
await OperationC("mybook.txt", book);
}
当然,您必须注意不再由UI线程执行Button1ClickedHandler,因此它无法触及任何UI项目(按钮,图形等)您还必须考虑如果要做什么,如果当动作仍然忙时,单击该按钮。
最后一个巧妙的技巧,你可以开始几个任务,并等到所有任务完成:
private async Task StartSeveralTasks()
{
var taskA = OperationA(),
var taskB = OperationB(),
var taskC = OperationC(...),
};
await Task.WhenAll(new Task[] {taskA, taskB, taskC});
// because taskB is a Task<string>, taskB has a property Result:
string book = taskB.Result;
}
Task.WhenAll包装System.AggregateException中任何任务抛出的所有异常。该类有一个属性InnerExceptions,它包含所有已发生异常的序列。
答案 1 :(得分:0)
您可以使用@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3)
在不同的线程中执行OperationB。像:
Task.Run()