網站首頁 編程語言 正文
異步執行 I/O 密集型操作是生產高響應和可伸縮應用程序及組件的關鍵??勺屇褂脴O少量的線程來執行大量的工作,而無需阻止任何線程。然而異步編程卻有些麻煩,許多程序員不愿意去做它。
網上有不少通過lambda 表達式和AsyncEnumerator 等來實現簡化異步編程的方法,這些方法也確實行之有效,但在.net 4.0中,我們又多了一種選擇——通過TaskFactory.FromAsync簡化APM。
TaskFactory.FromAsync這個方法非常簡單,通過它可以把一個異步的任務轉換為一個Task,首先我們來看一個簡單的例子吧:
static IEnumerable<Task> CopyStreamAsync(Stream input, Stream output)
{
var buffer = new byte[0x2000];
while (true)
{
var readTask = Task<int>.Factory.FromAsync(input.BeginRead, input.EndRead, buffer, 0, buffer.Length, null);
yield return readTask;
if (readTask.Result == 0)
break;
yield return Task.Factory.FromAsync(output.BeginWrite, output.EndWrite, buffer, 0, buffer.Length, null);
}
}
這個例子通過TaskFactory.FromAsync把一系列異步操作轉換為了一個任務列。雖然這些都是異步操作,但在函數中卻和同步操作一樣直觀,十分簡單而清晰。
轉換為了的任務列后,我們就需要來執行這一系列任務,最簡單的方法如下:
foreach (var task in CopyStreamAsync(input, output))
{
task.Wait();
}
這種方式雖然直接有效,但它卻是一種阻塞式的操作,沒有達到異步的目的,我們一般可以通過如下方式把這個任務列轉換為一個任務,從而實現異步執行。
public static Task Iterate(this TaskFactory factory, IEnumerable<Task> asyncIterator)
{
var scheduler = factory.Scheduler ?? TaskScheduler.Current;
// Get an enumerator from the enumerable
var enumerator = asyncIterator.GetEnumerator();
if (enumerator == null) throw new InvalidOperationException();
// Create the task to be returned to the caller. And ensure
// that when everything is done, the enumerator is cleaned up.
var trs = new TaskCompletionSource<object>(factory.CreationOptions);
trs.Task.ContinueWith(_ => enumerator.Dispose(), scheduler);
// This will be called every time more work can be done.
Action<Task> recursiveBody = null;
recursiveBody = antecedent =>
{
try
{
// If the previous task completed with any exceptions, bail
if (antecedent != null && antecedent.IsFaulted)
trs.TrySetException(antecedent.Exception);
else if (trs.Task.IsCanceled) trs.TrySetCanceled();
else if (enumerator.MoveNext())
enumerator.Current.ContinueWith(recursiveBody, scheduler);
// Otherwise, we're done!
else trs.TrySetResult(null);
}
// If MoveNext throws an exception, propagate that to the user
catch (Exception exc) { trs.TrySetException(exc); }
};
// Get things started by launching the first task
factory.StartNew(_ => recursiveBody(null), scheduler);
// Return the representative task to the user
return trs.Task;
}
這個函數我是摘錄自ParallelProgrammingSamples中的,里面還有好幾種其它的調用形式,可以根據需要選擇合適的方法。
原文鏈接:https://www.cnblogs.com/TianFang/archive/2009/11/07/1597953.html
相關推薦
- 2022-12-14 Android使用Room操作數據庫流程詳解_Android
- 2022-03-14 YUV420SP to JPEG
- 2024-01-30 關閉idea時出現waiting for process detach解決辦法
- 2022-05-31 利用python庫matplotlib繪制不同的圖表_python
- 2022-11-09 Android?使用maven?publish插件發布產物(aar)流程實踐_Android
- 2022-04-18 uniapp h5去掉默認的頂部導航
- 2022-12-07 C++小游戲教程之猜數游戲的實現_C 語言
- 2022-05-07 redis實現分布式session的解決方案_Redis
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支