Dot-Net
TPL 數據流管道設計基礎知識
我嘗試創建設計良好的 TPL 數據流管道,以優化系統資源的使用。我的項目是一個 HTML 解析器,它將解析後的值添加到 SQL Server DB 中。我已經有了未來管道的所有方法,現在我的問題是將它們放置在 Dataflow 塊中的最佳方法是什麼,我應該使用多少塊?一些方法受 CPU 限制,其中一些方法受 I/O 限制(從 Internet 載入,SQL Server DB 查詢)。現在我認為將每個 I/O 操作放在單獨的塊中是正確的方法,就像這個方案一樣:
在這種情況下設計管道的基本規則是什麼?
選擇如何劃分塊的一種方法是確定要獨立於其他部分縮放的部分。一個好的起點是將 CPU 綁定部分與 I/O 綁定部分分開。我會考慮合併最後兩個塊,因為它們都是 I/O 綁定的(可能是同一個數據庫)。
我發布了來自Concurrent Programming on Windows的範例通用管道。好的管道是平衡的管道,這意味著每個階段都不會在管道內出現瓶頸。根據範常式式碼,您可以創建盡可能多的執行緒來執行每個階段。
原始碼:
public class Pipeline<TSource, TDest> : IPipeline { private readonly IPipelineStage[] _stages; public Pipeline(Func<TSource, TDest> transform, int degree) : this (new IPipelineStage[0], transform, degree) {} internal Pipeline(IPipelineStage[] toCopy, Func<TSource, TDest> transform, int degree) { _stages = new IPipelineStage[toCopy.Length] + 1; Array.Copy(toCopy, _stages, _stages.Length); _stages[_stages.Length - 1] = new PipelineStage(transform, degree); } public Pipeline<TSource, TNew> AddStage<TNew>(Func<TDest, TNew> transform, degree) { return new Pipeline<TSource, TNew>(_stages, transform, degree); } public IEnumerator<TDest> GetEnumerator(IEnumerable<TSrouce> arg) { IEnumerable er = arg; CountdownEvent ev = null; for (int i = 0; i < _stages.Length; i++) er = _stages[i].Start(er, ref ev); foreach (TDest elem in ef) yield return elem; } } class PipelineStage<TInput, TOutput> : IPipelineStage { private readonly Func<TInput, TOutput> _transform; private readonly int _degree; internal PipelineStage(Func<TInput, TOutput> transform, int degree) { _transform = transform; _degree = degree; } internal IEnumerable Start(IEnumerable src) { //... } } interface IPipelineStage { IEnumerable Start(IEnumerable Src); }
