真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Task類在.NET4.5中的一些改進(jìn)

Task類在.NET4.5中,做了一些改進(jìn),比如新增了方法ConfigureAwait,Delay,Run等方法。其中一個重要修改,就是對于異常的處理。

在成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)過程中,需要針對客戶的行業(yè)特點(diǎn)、產(chǎn)品特性、目標(biāo)受眾和市場情況進(jìn)行定位分析,以確定網(wǎng)站的風(fēng)格、色彩、版式、交互等方面的設(shè)計方向。創(chuàng)新互聯(lián)還需要根據(jù)客戶的需求進(jìn)行功能模塊的開發(fā)和設(shè)計,包括內(nèi)容管理、前臺展示、用戶權(quán)限管理、數(shù)據(jù)統(tǒng)計和安全保護(hù)等功能。

在.NET4.0中,Task中拋出的異常,如果沒有去捕獲,在Task被垃圾回收的時候,析構(gòu)函數(shù)檢測到該Task對象還有未被處理過的異常,會拋出這個異常,并且導(dǎo)致進(jìn)程終結(jié),進(jìn)程終結(jié)的時間是由垃圾回收器和析構(gòu)方法決定的。(可以通過注冊TaskSchedular.UnobservedTaskException事件處理未捕獲的異常。)

ThrowUnobservedTaskExceptions節(jié)點(diǎn)

在.NET4.5中,微軟改變了策略,對于task中未處理的異常,默認(rèn)情況下不會導(dǎo)致殺死進(jìn)程。這個可以通過配置ThrowUnobservedTaskExceptions節(jié)點(diǎn)實(shí)現(xiàn)。

默認(rèn)情況下,ThrowUnobservedTaskExceptions這個節(jié)點(diǎn)的enabled=false。如下配置。


    
      
    

這種情況下,在.NET4.5中,GC回收對象的時候,是不會導(dǎo)致程序崩潰的,未捕獲的異常就這樣消失了。比如下面的代碼:

static void Main(string[] args)
{
      for (int i = 0; i < 10; i++)
      {
           var t = Task.Factory.StartNew(() => { throw new Exception("xxxxxx"); return 1; }
                        , CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
            }
      while (true)
     {
           GC.Collect();
           Thread.Sleep(1000);
      }
      Console.ReadKey();
}

但是如果設(shè)置,那么程序就會崩潰,這和在.NET4.0中的結(jié)局一樣。

Task類在.NET4.5中的一些改進(jìn)

Task類在.NET4.5中的一些改進(jìn)

當(dāng)然,對于所有的異常,都是建議捕獲并且處理的。.NET4.0和4.5都提供了TaskScheduler.UnobservedTaskException事件,通過監(jiān)聽這個事件,也可以捕獲到這個異常。

代碼如下:

TaskScheduler.UnobservedTaskException += (o, ev) =>
{
      Console.WriteLine(ev.Exception);
      ev.SetObserved();
      Console.WriteLine("---------");
};

注意:ev.SetObserved();方法必須要調(diào)用,這樣才能阻止進(jìn)程崩潰。

 

.NET4.0中Task的異常

還有一處改進(jìn)是對于異常的捕獲上。對于Task中拋出的異常,外部的try catch是無法捕獲的。例如:

static Task f()
{
try
{
  var t = Task.Factory.StartNew(() => { throw new Exception("xxxxxx"); return 1; });
  return t;
}
catch
{
  Console.WriteLine("error");
}
return null;
}

無論是在.net4.0還是.net4.5,上述代碼都是不會走到catch中的。只有當(dāng)運(yùn)行Task.Wait或者讀取Task.Result的時候(這些方法都會引起阻塞),才會拋出異常,由于運(yùn)行的Task可能是包含了多個子Task,或者在WaitAll多個Task,那么異??赡軙霈F(xiàn)多個。Task類會把這些異常包成AggregateException異常。要獲得異常的正真信息,需要訪問AggregateException.InnerExceptions屬性。如下代碼:

Task t1 = Task.Factory.StartNew(() =>
  {
   throw new Exception("error1");
  });
Task t2 = Task.Factory.StartNew(() =>
{
throw new Exception("error2");
});
Task t3 = Task.Factory.StartNew(() =>
{
throw new Exception("error3");
});
try
{
Task.WaitAll(t1,t2,t3);
}
catch (AggregateException ex)
{
Console.WriteLine("Exception Type:{0}", ex.GetType());
Console.WriteLine("Exception Message:{0}", ex.Message);
Console.WriteLine("Exception StackTrace:{0}", ex.StackTrace);
Console.WriteLine("Exception InnerException.Message:{0}", ex.InnerException.Message);
foreach (var innerEx in ex.InnerExceptions)
{
  Console.WriteLine("InnerExceptions.Message:{0}", innerEx.Message);
}
}

Task.WaitAll三個Task,捕獲異常的時候,類型為AggregateException,并且可以通過InnerExceptions,遍歷出每一個異常。這里值得注意的是,如果AggregateException的InnerExceptions有3個異常的話,AggregateException的InnerException會拋出哪個異常?根據(jù)老趙的說法,C#開發(fā)團(tuán)隊“故意”不提供文檔說明究竟會拋出哪個異常。因?yàn)樗麄儾⒉幌胱龀鲞@方面的約束,因?yàn)檫@部分行為一旦寫入文檔,便成為一個規(guī)定和限制,為了類庫的兼容性今后也無法對此做出修改。

上面代碼的輸出如下:

Task類在.NET4.5中的一些改進(jìn)Task類在.NET4.5中的一些改進(jìn)

 

async/await

在.net 4.5中,c#5.0的語法支持了async/await的寫法,這種寫法下,可以按照同步的思路寫異步方法。而且,異常處理也變得可以直接捕獲,在await的時候,代碼可以直接捕獲異常,例如下面的代碼。

static void Main(string[] args)
{
	var t = f();
	Console.ReadKey();
}
async static Task f()
{
	int val = 0;
	try
	{
		val = await Task.Factory.StartNew(() => { throw new NotSupportedException("xxxxxx"); return 1; });
	}
	catch (Exception ex)
	{
		Console.WriteLine("Exception Type:{0}", ex.GetType());
		Console.WriteLine("Exception Message:{0}", ex.Message);
		Console.WriteLine("Exception StackTrace:{0}", ex.StackTrace);
	}
	return val;
}

輸出如下:

Task類在.NET4.5中的一些改進(jìn)Task類在.NET4.5中的一些改進(jìn)

注意,可以看到錯誤的堆棧信息。從System.Threading.Tasks.Task類切換到了 System.Runtime.CompilerServices.TaskAwaiter。

C# 使用了SynchronizationContext類完成了這個切換。當(dāng)await一個Task的時候,當(dāng)前的 SynchronizationContext對象被存儲下來。當(dāng)方法繼續(xù)向下運(yùn)行的時候,await關(guān)鍵字的結(jié)構(gòu)使用Post方法,在之前保存的SynchronizationContext類的基礎(chǔ)上,繼續(xù)運(yùn)行該方法。更多細(xì)節(jié)不在這里描述。因此只要await關(guān)鍵字的方法上出現(xiàn)了異常,就可以捕獲掉,并且捕獲的異常類型,就可以不把異常往上層拋,還有一個不同點(diǎn)是await方法捕獲的異常類型就是直接的類型,而不是System.AggregateException。

但是如果在await等待是多個Task,并且這多個Task都拋出了異常,那么,最終捕獲的異常也會是System.AggregateException類型。并且也可以遍歷出所有的異常。和之前的處理同步情況下是一樣的。

static void Main(string[] args)
{
var t = f();
Console.WriteLine(t.Result);
Console.ReadKey();
}
async static Task f()
{
int val = 0;
Task all = null;
try
{
  Task t1 = Task.Factory.StartNew(() =>
  {
   throw new NotImplementedException("error1");
   return 1;
  });
  Task t2 = Task.Factory.StartNew(() =>
  {
   throw new NotImplementedException("error2");
   return 2;
  });
  Task t3 = Task.Factory.StartNew(() =>
  {
   throw new NotImplementedException("error3");
   return 3;
  });
await (all = Task.WhenAll(t1, t2, t3));
  val = all.Result.Sum();
}
catch (Exception ex)
{
  Console.WriteLine("Exception Type:{0}", ex.GetType());
  Console.WriteLine("Exception Message:{0}", ex.Message);
  Console.WriteLine("Exception StackTrace:{0}", ex.StackTrace);
  foreach (var innerEx in all.Exception.InnerExceptions)
  {
   Console.WriteLine("InnerExceptions.Message:{0}", innerEx.Message);
  }
}
return val;
}

輸出如下:

Task類在.NET4.5中的一些改進(jìn)Task類在.NET4.5中的一些改進(jìn)

上述代碼中,使用了WhenAll方法,返回的是一個Task類。由于t1,t2,t3中都包含了異常,因此返回的Task中有3個異常,但await關(guān)鍵字只會允許拋出一個具體的異常,因此,此處拋出了第一個異常。通過對all變量的遍歷,可以得到所有的異常。

WhenAll 方法

WhenAll方法是.NET4.5中新增的方法。它的返回值是一個Task,僅當(dāng)所有的Task都完成的時候,返回的這個Task才算完成,并且返回值可以是各個task返回值的一個數(shù)組。

因此可以把WhenAll方法看成是一組Task的合并。WhenAll和WaitAll有點(diǎn)類似,但本質(zhì)上很多不同。

1.調(diào)用Task.WaitAll的時候,會阻塞當(dāng)前線程,直到所有的Task都完成了。而Task.WhenAll方法不會阻塞當(dāng)前線程,而是直接返回了一個Task,只有在讀取這個Task的Result的時候,才會引起阻塞。

2.WaitAll的各類重載方法,它們的返回值是void或者bool,而WhenAll的返回值是Task。因此WhenAll方法更好的支持async/await異步寫法。

下面代碼演示W(wǎng)henAll方法:

static void Main(string[] args)
{
Task t1 = Task.Factory.StartNew(() =>
{
  Thread.Sleep(1000);
  return 1;
});
Task t2 = Task.Factory.StartNew(() =>
{
  Thread.Sleep(2000);
  return 2;
});
Task t3 = Task.Factory.StartNew(() =>
{
  Thread.Sleep(3000);
  return 3;
});
var all = Task.WhenAll(t1, t2, t3);
while (true)
{
  Console.WriteLine("{0} IsCompleted:{1}", DateTime.Now.ToString("HH:mm:ss fff"), all.IsCompleted);
  Thread.Sleep(200);
  if (all.IsCompleted)
   break;
}
var c = all.Result;
Console.WriteLine(c.Sum());
}

輸出的結(jié)果為:

Task類在.NET4.5中的一些改進(jìn)Task類在.NET4.5中的一些改進(jìn)

ConfigureAwait方法

ConfigureAwait方法的作用是指定代碼在執(zhí)行await操作的時候,是否捕獲上下文,捕獲上下文會帶來性能開銷。不捕獲上下文,在ASP.NET或者GUI程序時,可能帶來問題。更多的細(xì)節(jié)可以參考Stephen Cleary 的異步編程中的最佳做法

總之,.NET4.5中的Task的一些改進(jìn),都是為了迎合異步async/await的寫法而做出的改進(jìn)。更多參考資料:

http://msdn.microsoft.com/zh-cn/magazine/jj991977.aspx

http://msdn.microsoft.com/zh-cn/magazine/gg598924.aspx

以及Stephen Cleary的blog:http://blog.stephencleary.com/


網(wǎng)站標(biāo)題:Task類在.NET4.5中的一些改進(jìn)
當(dāng)前URL:http://weahome.cn/article/gsdjgc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部