Python3 與 C# 並發編程之~ 上篇

來源:互聯網
上載者:User

標籤:method   proc   nuget   cli   資源   傳統   網路操作   task   多個   

NetCore並發編程

範例程式碼:https://github.com/lotapp/BaseCode/tree/master/netcore/4_Concurrency

先簡單說下概念(其實之前也有說,所以簡說下):

  1. 並發:同時做多件事情
  2. 多線程:並發的一種形式
  3. 平行處理:多線程的一種(線程池產生的一種並發類型,eg:非同步編程
  4. 響應式編程:一種編程模式,對事件進行響應(有點類似於JQ的事件)

Net裡面很少用進程,在以前基本上都是線程+池+非同步+並行+協程

我這邊簡單引入一下,畢竟主要是寫Python的教程,Net只是幫你們回顧一下,如果你發現還沒聽過這些概念,或者你的項目中還充斥著各種ThreadThreadPool的話,真的得系統的學習一下了,現在官網的文檔已經很完善了,記得早幾年啥都沒有,也只能挖那些外國開源項目:

https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-processing-and-concurrency

1.非同步編程(Task)

Task的目的其實就是為了簡化ThreadThreadPool的代碼,下面一起看看吧:

非同步用起來比較簡單,一般IO,DB,Net用的比較多,很多時候都會採用重試機制,舉個簡單的例子:

/// <summary>/// 類比一個網路操作(別忘了重試機制)/// </summary>/// <param name="url">url</param>/// <returns></returns>private async static Task<string> DownloadStringAsync(string url){    using (var client = new HttpClient())    {        // 設定第一次重試時間        var nextDelay = TimeSpan.FromSeconds(1);        for (int i = 0; i < 3; i++)        {            try            {                return await client.GetStringAsync(url);            }            catch { }            await Task.Delay(nextDelay); // 用非同步阻塞的方式防止伺服器被太多重試給阻塞了            nextDelay *= 2; // 3次重試機會,第一次1s,第二次2s,第三次4s        }        // 最後一次嘗試,錯誤就拋出        return await client.GetStringAsync(url);    }}

然後補充說下Task異常的問題,當你await的時候如果有異常會拋出,在第一個await處捕獲處理即可

如果asyncawait就是理解不了的可以這樣想:async就是為了讓await生效(為了向後相容)

對了,如果返回的是void,你設定成Task就行了,觸發是類似於事件之類的方法才使用void,不然沒有傳回值都是使用Task

項目裡經常有這麼一個情境:等待一組任務完成後再執行某個操作,看個引入案例:

/// <summary>/// 1.批量任務/// </summary>/// <param name="list"></param>/// <returns></returns>private async static Task<string[]> DownloadStringAsync(IEnumerable<string> list){    using (var client = new HttpClient())    {        var tasks = list.Select(url => client.GetStringAsync(url)).ToArray();        return await Task.WhenAll(tasks);    }}

再舉一個情境:同時調用多個同效果的API,有一個返回就好了,其他的忽略

/// <summary>/// 2.返回首先完成的Task/// </summary>/// <param name="list"></param>/// <returns></returns>private static async Task<string> GetIPAsync(IEnumerable<string> list){    using (var client = new HttpClient())    {        var tasks = list.Select(url => client.GetStringAsync(url)).ToArray();        var task = await Task.WhenAny(tasks); // 返回第一個完成的Task        return await task;    }}

一個async方法被await調用後,當它恢複運行時就會回到原來的上下文中運行。

如果你的Task不再需要上下文了可以使用:task.ConfigureAwait(false),eg:寫個日記還要啥上下文?

逆天的建議是:在核心代碼裡面一種使用ConfigureAwait,使用者頁面相關代碼,不需要內容相關的加上

其實如果有太多await在上下文裡恢複那也是比較卡的,使用ConfigureAwait之後,被暫停後會線上程池裡面繼續運行

再看一個情境:比如一個耗時操作,我需要指定它的逾時時間:

 /// <summary>/// 3.逾時取消/// </summary>/// <returns></returns>private static async Task<string> CancellMethod(){    //執行個體化取消任務    var cts = new CancellationTokenSource();    cts.CancelAfter(TimeSpan.FromSeconds(3)); // 設定失效時間為3s    try    {        return await DoSomethingAsync(cts.Token);    }    // 任務已經取消會引發TaskCanceledException    catch (TaskCanceledException ex)    {        return "false";    }}/// <summary>/// 模仿一個耗時操作/// </summary>/// <returns></returns>private static async Task<string> DoSomethingAsync(CancellationToken token){    await Task.Delay(TimeSpan.FromSeconds(5), token);    return "ok";}

非同步這塊簡單回顧就不說了,留兩個擴充,你們自行探討:

  1. 進度方面的可以使用IProgress<T>,就當留個作業自己摸索下吧~
  2. 使用了非同步之後盡量避免使用task.Wait or task.Result,這樣可以避免死結

Task其他新特徵去官網看看吧,引入到此為止了。

2.並行編程(Parallel)

這個其實出來很久了,現在基本上都是用PLinq比較多點,主要就是:

  1. 資料並行:重點在處理資料(eg:彙總)
  2. 任務並行:重點在執行任務(每個任務塊儘可能獨立,越獨立效率越高)
資料並行

以前都是Parallel.ForEach這麼用,現在和Linq結合之後非常方便.AsParallel()就OK了

說很抽象看個簡單案例:

static void Main(string[] args){    IEnumerable<int> list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9 };    foreach (var item in ParallelMethod(list))    {        Console.WriteLine(item);    }}/// <summary>/// 舉個例子/// </summary>private static IEnumerable<int> ParallelMethod(IEnumerable<int> list){    return list.AsParallel().Select(x => x * x);}

正常執行的結果應該是:

1492564164981

並行之後就是這樣了(不管順序了):

2564194981416

當然了,如果你就是對順序有要求可以使用:.AsOrdered()

/// <summary>/// 舉個例子/// </summary>private static IEnumerable<int> ParallelMethod(IEnumerable<int> list){    return list.AsParallel().AsOrdered().Select(x => x * x);}

其實實際項目中,使用並行的時候:任務時間適中,太長不適合,太短也不適合

記得大家在項目裡經常會用到如SumCount等彙總函式,其實這時候使用並行就很合適

var list = new List<long>();for (long i = 0; i < 1000000; i++){    list.Add(i);}Console.WriteLine(GetSumParallel(list));
private static long GetSumParallel(IEnumerable<long> list){    return list.AsParallel().Sum();}

time dotnet PLINQ.dll

499999500000real    0m0.096suser    0m0.081ssys 0m0.025s

不使用並行:(稍微多了點,CPU越密集差距越大)

499999500000real    0m0.103suser    0m0.092ssys 0m0.021s

其實彙總有一個通用方法,可以支援複雜的彙總:(以上面sum為例)

.Aggregate(            seed:0,            func:(sum,item)=>sum+item          );

稍微擴充一下,PLinq也是支援取消的,.WithCancellation(CancellationToken)

Token的用法和上面一樣,就不複述了,如果需要和非同步結合,一個Task.Run就可以把並行任務交給線程池了

也可以使用Task的非同步方法呼叫,設定逾時時間,這樣PLinq逾時了也就終止了

PLinq這麼方便,其實也是有一些小弊端的,比如它會直接最大程度的佔用系統資源,可能會影響其他的任務,而傳統的Parallel則會動態調整

任務並行(並行調用)

這個PLinq好像沒有對應的方法,有新文法你可以說下,來舉個例子:

await Task.Run(() =>    Parallel.Invoke(        () => Task.Delay(TimeSpan.FromSeconds(3)),        () => Task.Delay(TimeSpan.FromSeconds(2))    ));

取消也支援:

Parallel.Invoke(new ParallelOptions() { CancellationToken = token }, actions);
擴充說明

其實還有一些比如資料流響應編程沒說,這個之前都是用第三方庫,剛才看官網文檔,好像已經支援了,所以就不賣弄了,感興趣的可以去看看,其實項目裡面有流資料相關的架構,eg:Spark,都是比較成熟的解決方案了基本上也不太使用這些了。

然後還有一些沒說,比如NetCore裡面不可變類型(列表、字典、集合、隊列、棧、安全執行緒字典等等)以及限流任務調度等,這些關鍵詞我提一下,也方便你去搜尋自己學習拓展

先到這吧,其他的自己探索一下吧,最後貼一些Nuget庫,你可以針對性的使用:

資料流Microsoft.Tpl.Dataflow
響應編程(Linq的Rx操作):Rx-Main
不可變類型Microsoft.Bcl.Immutable

Python3 與 C# 並發編程之~ 上篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.