在Task上执行长时间运行的I / O方法(Execute long running I/O method on Task)

编程入门 行业动态 更新时间:2024-10-28 10:25:41
在Task上执行长时间运行的I / O方法(Execute long running I/O method on Task)

我有一个WCF操作Say Service1.OperationA。 此操作必须调用另一个Operartion Service2.OprationB。 OperationB被称为OperationA的最后一步。 OperationB返回true或false。

操作B对数据库执行一些读写操作,可能需要很长时间。 从操作B调用此方法时,我不想等待OperationB的结果。 即使抛出异常,我也会捕获并记录异常。 还有其他操作,如OperationC,可能要等待OperationB的结果。

我可以使用Task在OperationC中运行OperationB,因为它需要很长时间。 可以在Task上调用I / O操作吗?

I have a WCF operation Say Service1.OperationA. This operation has to call another Operartion Service2.OprationB. OperationB is called as last step in OperationA. OperationB returns just true or false.

Operation B does some read and writes to database and it might take long time. When Calling this method from operation B, I do not want to wait for the result of OperationB. Even if throws exception I will catch and log the exception. There are other operations like OperationC which might want to wait for the result of OperationB.

Can I use Task to run OperationB within OperationC conidering it takes long time. Is it okay to call I/O operations on Task?

最满意答案

最简单的方法是使用async-await。

如果您的过程需要一些时间,请将过程声明为异步 而不是返回void返回Task,而不是TResult返回Task <TResult > 在此过程中,以正常的同步方式执行您要执行的操作。 每当有人打电话给可能需要一些时间的东西时,请寻找一个等待它的版本。 此函数通常具有扩展异步。 大多数I / O函数都具有异步版本。 像TextWriter.WriteAsync一样

在异步函数中,只需调用另一个异步函数即可。 如果您需要结果,请立即使用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); }

当然,如果您不需要结果,请不要等待它。 调用另一个异步函数,并在准备就绪时返回。 您可能会收到编译器警告,表示您没有等待,但这不是您想要的吗?

异步函数只能由其他异步函数调用 每个异步函数都返回Task或Task <TResult > 有一个例外:事件处理程序可能返回void

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); }

即使您没有显式启动任务,async也会使您的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,其中包含所有已发生异常的序列。

The most easy method is to use async-await.

If you have a procedure that takes some time, declare the procedure async Instead of void return Task, instead of TResult return Task<TResult> Inside this procedure do what you want to do in normal synchronous way. Whenever there is a call to something that might take some time, look for an awaitable version of it. Quite often this function has the extension async. Most I/O functions have an async version. Like TextWriter.WriteAsync

In your async function just call the other async function. If you need the result immediately use await, if you have something else to do, do this while the async function is performing and await for the Task when you need the result.

Let's suppose your slow OperationB downloads the complete Shakespeare. As an async function this would be like:

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); } }

If OperationA is async and you want to wait for the result of OperationB, await for the result:

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); }

Of course, if you don't need the result, don't await for it. Call the other async function and return whenever you are ready. You'll probably get a compiler warning that you don't await, but wasn't that what you wanted?

an async function can only be called by other async functions Every async function returns Task or Task<TResult> There is one exception: the event handler may return void

.

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. }

The problem is, if you want to do something with the result, no one will know that OperationBAsync is finished. Suppose you have an operationCAsync that writes the read data:

private async Task OperationCAsync(string filename, string text) { using (var textWriter = new StreamWriter(fileName)) { await WriteAsync(text); } }

The easiest method would be that the calling functions would wait:

private async void Button1_Clicked(object sender, ...) { await OperationAAsync(); var book = await OperationBAsync(); await OperationC("mybook.txt", book); }

Even though you don't start a task explicitly, the async makes that your UI keeps responsive during the times that the functions are awaiting. Be aware though that it still is the UI thread that does the processing, so while the code is not awaiting, your UI thread will be busy. If you really want to free the UI from this burden, you'll need to start a seperate thread:

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); }

Of course you'll have to take care that Button1ClickedHandler is not performed by the UI thread anymore, so it can't touch any UI item (buttons, graphs etc) You'll also have to think about what to do if the button is clicked while the action is still busy.

Finally a neat trick, you can start several tasks, and wait until all are finished:

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 wraps all exceptions thrown by any of the tasks in an System.AggregateException. This class has a property InnerExceptions that contains the sequence of all occurred exceptions.

更多推荐

本文发布于:2023-07-18 19:21:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1164457.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:长时间   方法   Task   Execute   method

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!