C#並發編程·經典執行個體讀書筆記

來源:互聯網
上載者:User
前言

最近在看《C# 並發編程 · 經典執行個體》這本書,這不是一本理論書,反而這是一本主要講述怎麼樣更好的使用好目前 C#.NET 為我們提供的這些 API 的一本書,書中絕大部分是一些執行個體,在日常開發中還是經常會使用到。

書中一些觀點還是比較贊同,比如作者說目前絕大多數的圖書對關於並發多線程等這些內容放到最後,而缺少一本介紹並發編程的入門指引和參考。

另外一個觀點是絕大多數國內的技術人員認為技術越底層就牛逼,而做上層應用的就是“碼農”,作者反對了這一觀點,其實能利用好現有的庫也是一種能力,雖然說理解基礎知識對日常生活仍然有協助,但最好從更進階的抽象概念來學習。

非同步基礎

任務暫停,休眠

非同步方式暫停或者休眠任務,可以使用 Task.Delay();

static async Task<T> DelayResult<T>(T result, TimeSpan delay) {    await Task.Delay(delay);    return result;}

非同步重試機制

一個簡單的指數退避策略,重試的時間會逐次增加,在訪問 Web 服務時,一般採用此種策略。

static async Task<string> DownloadString(string uri) {    using (var client = new HttpClient()) {        var nextDealy = TimeSpan.FromSeconds(1);        for (int i = 0; i != 3; ++i) {            try {                return await client.GetStringAsync(uri);            }            catch {            }            await Task.Delay(nextDealy);            nextDealy = nextDealy + nextDealy;        }        //最後重試一次,拋出出錯資訊                   return await client.GetStringAsync(uri);    }}

報告進度

非同步作業中,經常需要展示操作進度,可以使用 IProcess<T> 和 Process<T>。

static async Task MyMethodAsync(IProgress<double> progress) {    double precentComplete = 0;    bool done = false;    while (!done) {        await Task.Delay(100);        if (progress != null) {            progress.Report(precentComplete);        }        precentComplete++;        if (precentComplete == 100) {            done = true;        }    }}public static void Main(string[] args) {    Console.WriteLine("starting...");    var progress = new Progress<double>();    progress.ProgressChanged += (sender, e) => {        Console.WriteLine(e);    };    MyMethodAsync(progress).Wait();    Console.WriteLine("finished");}

等待一組任務

同時執行幾個任務,等待他們全部完成

Task task1 = Task.Delay(TimeSpan.FromSeconds(1));Task task2 = Task.Delay(TimeSpan.FromSeconds(2));Task task3 = Task.Delay(TimeSpan.FromSeconds(1));Task.WhenAll(task1, task2, task3).Wait();

等待任意一個任務完成

執行若干任務,只需要對其中一個的完成進行響應。主要用於對一個操作進行多種獨立的嘗試,只要其中一個嘗試完成,任務就算完成。

static async Task<int> FirstResponseUrlAsync(string urlA, string urlB) {    var httpClient = new HttpClient();    Task<byte[]> downloadTaskA = httpClient.GetByteArrayAsync(urlA);    Task<byte[]> downloadTaskB = httpClient.GetByteArrayAsync(urlB);    Task<byte[]> completedTask = await Task.WhenAny(downloadTaskA, downloadTaskB);    byte[] data = await completedTask;    return data.Length;}

集合

不可變棧和隊列

需要一個不會經常修改,可以被多個安全執行緒訪問的棧和隊列。他們的API和 Stack<T> 和 Queue<T> 非常相似。效能上,不可變棧(LIFO)和隊列(FIFO)與標準的棧和隊列具有相同的時間複雜度。但是在需要頻繁修改的簡單情況下,標準棧和隊列速度更快。

在內部實現上,當對一個對象進行覆蓋(重新賦值)的時候,不可變集合採用的是返回一個修改過的集合,原創組合引用是不變化的,也就是說如果另外一個變數引用了相同的對象,那麼它(另外的變數)是不會變化的。

ImmutableStack

var stack = ImmutableStack<int>.Empty;stack = stack.Push(11);  var biggerstack = stack.Push(12);foreach (var item in biggerstack) {    Console.WriteLine(item);}  // output: 12 11int lastItem;stack = stack.Pop(out lastItem);Console.WriteLine(lastItem);  //output: 11

實際上,兩個棧內部共用了儲存 11 的記憶體,這種實現方式效率很高,而且每個執行個體都是安全執行緒的。

ImmutableQueue

var queue = ImmutableQueue<int>.Empty;queue = queue.Enqueue(11);queue = queue.Enqueue(12);foreach (var item in queue) {    Console.WriteLine(item);} // output: 11  12int nextItem;queue = queue.Dequeue(out nextItem);Console.WriteLine(nextItem); //output: 11

不可變列表和集合

ImmutableList

時間複雜度

有些時候需要這樣一個資料結構:支援索引,不經常修改,可以被多安全執行緒的訪問。

var list = ImmutableList<int>.Empty;list = list.Insert(0, 11);list = list.Insert(0, 12);foreach (var item in list) {    Console.WriteLine(item);} // 12 11

ImmutableList<T> 可以索引,但是注意效能問題,不能用它來簡單的替代 List<T>。它的內部實現是用的二叉樹組織的資料,這麼做是為了讓不同的執行個體之間共用記憶體。

ImmutableHashSet

有些時候需要這樣一個資料結構:不需要存放重複內容,不經常修改,可以被多個安全執行緒訪問。時間複雜度 O(log N)。

var set = ImmutableHashSet<int>.Empty;set = set.Add(11);set = set.Add(12);foreach (var item in set) {    Console.WriteLine(item);} // 11 12 順序不定

安全執行緒字典

一個安全執行緒的索引值對集合,多個線程讀寫仍然能保持同步。

ConcurrentDictionary

混合使用了細粒度的鎖定和無鎖技術,它是最實用的集合類型之一。

var dictionary = new ConcurrentDictionary<int, string>();dictionary.AddOrUpdate(0, key => "Zero", (key, oldValue) => "Zero");

如果多個線程讀寫一個共用集合,實用 ConcurrentDictionary<TKey,TValue> 是最合適的。如果不會頻繁修改,那麼更適合使用 ImmutableDictionary<TKey,TValue> 。

它最適合用於在需要共用資料的場合,即多個線程共用一個集合,如果一些線程只添加元素一些線程只移除元素,那最好使用 生產者/消費者集合(BlockingCollection<T>)。

初始化共用資源

程式多個地方使用一個值,第一次訪問時對它進行初始化。

static int _simpleVluae;static readonly Lazy<Task<int>> shardAsyncInteger =    new Lazy<Task<int>>(async () => {        await Task.Delay(2000).ConfigureAwait(false);        return _simpleVluae++;    });public static void Main(string[] args) {    int shareValue = shardAsyncInteger.Value.Result;    Console.WriteLine(shareValue); // 0    shareValue = shardAsyncInteger.Value.Result;    Console.WriteLine(shareValue); // 0    shareValue = shardAsyncInteger.Value.Result;    Console.WriteLine(shareValue); // 0}

以上就是C#並發編程·經典執行個體讀書筆記的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.