溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何在.NET Core中使用異步編程

發(fā)布時(shí)間:2021-05-17 17:05:38 來(lái)源:億速云 閱讀:213 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

今天就跟大家聊聊有關(guān)如何在.NET Core中使用異步編程,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

1. 同步方法

static void Main(string[] args)
{
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:開(kāi)始");
  // 調(diào)用同步方法
  SyncTestMethod();
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:結(jié)束");
  Console.ReadKey();
}

/// <summary>
/// 同步方法
/// </summary>
static void SyncTestMethod()
{
  for (int i = 0; i < 10; i++)
  {
    var str = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:SyncTestMethod{i}";
    Console.WriteLine(str);
    Thread.Sleep(10);
  }
}

控制臺(tái)打?。?/p>

2019-03-26 14:44:05 445:開(kāi)始
2019-03-26 14:44:05 445:SyncTestMethod0
2019-03-26 14:44:05 445:SyncTestMethod1
2019-03-26 14:44:05 445:SyncTestMethod2
2019-03-26 14:44:05 445:SyncTestMethod3
2019-03-26 14:44:05 445:SyncTestMethod4
2019-03-26 14:44:05 445:SyncTestMethod5
2019-03-26 14:44:05 445:SyncTestMethod6
2019-03-26 14:44:05 445:SyncTestMethod7
2019-03-26 14:44:05 445:SyncTestMethod8
2019-03-26 14:44:05 445:SyncTestMethod9
2019-03-26 14:44:05 445:結(jié)束

主線程在調(diào)用同步方法時(shí),會(huì)直接在主線程中執(zhí)行同步方法,這個(gè)時(shí)候若SyncTestMethod方法后面還有其它方法,都需要等待SyncTestMethod執(zhí)行完成。

如何在.NET Core中使用異步編程 

2. 異步方法

static void Main(string[] args)
{
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:開(kāi)始");
  // 調(diào)用異步步方法
  AsyncTestMethod();
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:結(jié)束");
  Console.ReadKey();
}


/// <summary>
/// 異步方法
/// </summary>
/// <returns></returns>
static async Task AsyncTestMethod() {
  await Task.Run(() => {
    for (int i = 0; i < 10; i++)
    {
      Console.WriteLine($"AsyncTestMethod");
      Thread.Sleep(10);
    }
  });
}

控制臺(tái)打?。?/p>

2019-03-26 14:52:37 5237:開(kāi)始
2019-03-26 14:52:37 5237:結(jié)束
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod
2019-03-26 14:52:37 5237:AsyncTestMethod

主線程在調(diào)用異步方法時(shí),將會(huì)新建一個(gè)子線程去執(zhí)行異步方法,調(diào)用過(guò)AsyncTestMethod方法之后,將會(huì)直接執(zhí)行AsyncTestMethod后面的方法,這個(gè)時(shí)候主線程不會(huì)等待異步方法執(zhí)行完成;因?yàn)檫@個(gè)時(shí)候主線程無(wú)法知曉異步方法會(huì)在什么時(shí)候執(zhí)行完成,所以此時(shí)也無(wú)法在主線程中直接獲取異步方法的返回,如果需要在異步方法執(zhí)行完成之后再在主線程中執(zhí)行其它方法,則需要使用Wait()來(lái)等待異步子線程執(zhí)行完成。

如何在.NET Core中使用異步編程

3. 等待(awiat)異步方法

static void Main(string[] args)
{
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:開(kāi)始");
  // 調(diào)用異步步方法
  AsyncTestMethod();
  // 等待異步方法執(zhí)行完成
  m1.Wait();
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:結(jié)束");
  Console.ReadKey();
}


/// <summary>
/// 異步方法
/// </summary>
/// <returns></returns>
static async Task AsyncTestMethod() {
  await Task.Run(() => {
    for (int i = 0; i < 10; i++)
    {
      Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:AsyncTestMethod");
      Thread.Sleep(10);
    }
  });
}

控制臺(tái)打?。?/p>

2019-03-26 14:55:51 5551:開(kāi)始
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:AsyncTestMethod
2019-03-26 14:55:51 5551:結(jié)束

主線程在調(diào)用異步方法時(shí),將會(huì)新建一個(gè)子線程去執(zhí)行異步方法,并且在調(diào)用AsyncTestMethod方法之后執(zhí)行了對(duì)AsyncTestMethod方法的等待Wait(),這個(gè)時(shí)候主線程會(huì)等待異步方法執(zhí)行完成,不會(huì)執(zhí)行后續(xù)的方法,在AsyncTestMethod執(zhí)行完成之后,等待結(jié)束,此時(shí)可以拿到異步方法AsyncTestMethod的返回值,然后再繼續(xù)執(zhí)行主線程中的方法。

如何在.NET Core中使用異步編程

4. 同步線程和異步線程關(guān)聯(lián)執(zhí)行

如有以下方法:

static int Method1()
{
  Thread.Sleep(200);
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我計(jì)算了一個(gè)值耗費(fèi)200ms");
  return 1;
}
static int Method200ms()
{
  Thread.Sleep(200);
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我做了一件耗費(fèi)200ms的事情");
  return 200;
}
static int Method500ms(int index)
{
  Thread.Sleep(500);
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我做了一件耗費(fèi)500ms的事情");
  return ++index;
}
static int Method1000ms()
{
  Thread.Sleep(1000);
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我做了一件耗費(fèi)1000ms的事情");
  return 1000;
}

Method500ms()需要Method1()的返回值作為參數(shù),如果所有的方法同步執(zhí)行在最后計(jì)算a、b、c、d的和:

static void Main(string[] args)
{
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:開(kāi)始");
  var a = Method1();
  var b = Method200ms();
  var c = Method500ms(a);
  var d = Method1000ms();
  var result = a+b+c+d;
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:最后得到的結(jié)果{result}");
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:結(jié)束");
  Console.ReadKey();
}

控制臺(tái)打?。?/p>

2019-03-26 15:10:06 106:開(kāi)始
2019-03-26 15:10:06 106:我計(jì)算了一個(gè)值耗費(fèi)200ms
2019-03-26 15:10:06 106:我做了一件耗費(fèi)200ms的事情
2019-03-26 15:10:07 107:我做了一件耗費(fèi)500ms的事情
2019-03-26 15:10:08 108:我做了一件耗費(fèi)1000ms的事情
2019-03-26 15:10:08 108:最后得到的結(jié)果1203
2019-03-26 15:10:08 108:結(jié)束

同步執(zhí)行的時(shí)候,需要逐一等待所有的方法執(zhí)行完成,花費(fèi)的時(shí)間顯然是所有的方法耗費(fèi)的時(shí)間之和。

如何在.NET Core中使用異步編程

對(duì)于以上四個(gè)方法,如果使用異步的方式來(lái)執(zhí)行,將會(huì)很大程度的節(jié)省程序的運(yùn)行時(shí)間,修改方法如下:

static async Task<int> AsyncMethod1()
{
  await Task.Run(()=> {
    Thread.Sleep(200);
    Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我計(jì)算了一個(gè)值耗費(fèi)200ms");
  });
  return 1;
}
static async Task<int> AsyncMethod200ms()
{
  await Task.Run(() => {
    Thread.Sleep(200);
    Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我做了一件耗費(fèi)200ms的事情");
  });
  return 200;
}
static async Task<int> AsyncMethod500ms(int index)
{
  await Task.Run(() => {
    Thread.Sleep(500);
    Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我做了一件耗費(fèi)500ms的事情");
  });
  return ++index;
}
static async Task<int> AsyncMethod1000ms()
{
  await Task.Run(() => {
    Thread.Sleep(1000);
    Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:我做了一件耗費(fèi)1000ms的事情");
  });
  return 1000;
}

使用異步的方式來(lái)調(diào)用方法:

static void Main(string[] args)
{
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:開(kāi)始");
  var m1 = AsyncMethod1();
  var m2 = AsyncMethod200ms();
  var m4 = AsyncMethod1000ms();
  m1.Wait();
  var m3 = AsyncMethod500ms(m1.Result);
  m2.Wait();
  m3.Wait();
  m4.Wait();
  var result = m1.Result + m2.Result + m3.Result + m4.Result;
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:最后得到的結(jié)果{result}");
  Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ms")}:結(jié)束");
  Console.ReadKey();
}

控制臺(tái)打印:

2019-03-26 14:11:54 1154:開(kāi)始
2019-03-26 14:11:54 1154:我計(jì)算了一個(gè)值耗費(fèi)200ms
2019-03-26 14:11:54 1154:我做了一件耗費(fèi)200ms的事情
2019-03-26 14:11:55 1155:我做了一件耗費(fèi)500ms的事情
2019-03-26 14:11:55 1155:我做了一件耗費(fèi)1000ms的事情
2019-03-26 14:11:55 1155:最后得到的結(jié)果1203
2019-03-26 14:11:55 1155:結(jié)束

因?yàn)?AsyncMethod500ms() 依賴于 AsyncMethod1() 的返回結(jié)果作為參數(shù),所以我們可以先直接以異步的方式運(yùn)行 AsyncMethod1() , AsyncMethod200ms() , AsyncMethod1000ms() 三個(gè)方法,這個(gè)時(shí)候三個(gè)方法都會(huì)建立異步的子線程進(jìn)行執(zhí)行,但是后面的 AsyncMethod500ms() 想要執(zhí)行,必須的有 AsyncMethod1() 的返回值,所以這個(gè)時(shí)候?qū)?AsyncMethod1() 進(jìn)行等待, 200ms 后, AsyncMethod1() 執(zhí)行完成, m1.Wait() 等待結(jié)束,繼續(xù)執(zhí)行 AsyncMethod500ms() ,并傳入了 AsyncMethod1() 的返回值 m1.Result ,最后因?yàn)樾枰獙?duì)四個(gè)方法的返回值進(jìn)行累加,所以在這之前必須保證其它三個(gè)方法也執(zhí)行完成,所以需要分別對(duì) AsyncMethod500ms()AsyncMethod200ms() , AsyncMethod1000ms() 進(jìn)行等待(Wait),因?yàn)榇丝趟械姆椒ǘ际钱惒綀?zhí)行的,所以程序的執(zhí)行時(shí)間將≈執(zhí)行時(shí)間最長(zhǎng)的那個(gè)方法的執(zhí)行時(shí)間( AsyncMethod1000ms() 執(zhí)行 1000ms ,執(zhí)行時(shí)間最長(zhǎng),程序的執(zhí)行時(shí)間≈ 1000ms )。

如何在.NET Core中使用異步編程

看完上面的內(nèi)容,可以確定的是,在某些情況下,異步編程能夠很大的提高我們程序運(yùn)行的效率,但是大家都在推崇的多使用異步編程不僅僅是因?yàn)檐浖厦娴脑?,在硬件上也有著很大的原因?/p>

前段時(shí)間我們將原來(lái)跑在一臺(tái)辦公電腦的程序發(fā)布到一臺(tái)雙路E5的DELL的刀片機(jī)上面去,結(jié)果發(fā)現(xiàn)在DELL刀片機(jī)上面運(yùn)行的性能竟然比之前的辦公電腦還差,開(kāi)始我們懷疑是DELL刀片機(jī)使用的是虛擬機(jī)的問(wèn)題,可能在某些地方?jīng)]有設(shè)置好,后來(lái)經(jīng)過(guò)一系列的服務(wù)器性能測(cè)試,無(wú)論是CPU處理速度、磁盤IO還是網(wǎng)絡(luò)帶寬,DELL刀片機(jī)都遠(yuǎn)超我們之前的那臺(tái)辦公電腦,但是我們運(yùn)行的程序中的某個(gè)接口在效率上就是不如之前的辦公電腦?。。?/p>

???(直到后來(lái)的某一天,隨著我對(duì).NET Core異步編程的理解的加深,終于明白是什么原因。)

我們先來(lái)看一下我們?nèi)粘i_(kāi)發(fā)使用的Intel CPU和服務(wù)器使用的CPU對(duì)比

開(kāi)發(fā)電腦CPU: 英特爾&reg; 酷睿? i5+8500 處理器

  • 處理器基本頻率:3GHz

  • 最大睿頻頻率:4.1GHz

  • 內(nèi)核數(shù):六核心

  • 線程數(shù):六線程

服務(wù)器CPU: 英特爾&reg; 至強(qiáng)&reg; D-2177NT 處理器

  • 處理器基本頻率:1.90 GHz

  • 最大睿頻頻率:3.00 GHz

  • 內(nèi)核數(shù):14

  • 線程數(shù):28

從上面的對(duì)比我們可以發(fā)現(xiàn)兩者之間的差異很明顯, i5 處理器的基本頻率和最大睿頻都高于服務(wù)器使用的 至強(qiáng) 處理器,但是在內(nèi)核數(shù)量和線程數(shù)量上面卻遠(yuǎn)遠(yuǎn)不如 至強(qiáng) ,如果我們的程序全部使用的同步編程的話,以WebApi為例,每一次請(qǐng)求中調(diào)用的方法都只是在CPU的某一個(gè)內(nèi)核/線程中進(jìn)行的,換句話說(shuō),CPU單核頻率的高低直接影響著同步方法的執(zhí)行效率,而我們之前的程序幾乎都是使用了同步方法,在辦公電腦上的 i5 處理器和服務(wù)器使用的 至強(qiáng) 處理器的單核頻率的差異顯然就是之前性能問(wèn)題的直接原因。

并且鑒于服務(wù)器CPU的特性(單核頻率低,內(nèi)核/線程數(shù)多),在程序中多使用異步/多線程的方式對(duì)于程序的性能而言是無(wú)容置疑的。

注意:

雖然異步編程很多時(shí)候能提升程序的效率,但不并意味著需要為了使用異步而將所有的方法改為異步執(zhí)行,如果同步執(zhí)行的開(kāi)銷甚至比創(chuàng)建一個(gè)異步線程開(kāi)銷還低的時(shí)候,就完全沒(méi)有必要再此處使用異步的方式。至于這其中的權(quán)衡利弊,或許需要一定的經(jīng)驗(yàn)才能拿捏的住。

看完上述內(nèi)容,你們對(duì)如何在.NET Core中使用異步編程有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI