《ASP.NET Core 高性能系列》致敬偉大的.NET斗士甲骨文!


寫在開始

  三年前,曾寫過一篇文章:從.NET和Java之爭談IT這個行業,當時遭到某些自認為懂得java就了不起的Javaer抨擊,

現在可以致敬偉大的.NET斗士甲骨文了

  (JDK8以上都需要收費,Android棄用java作為第一語言,別高興:OpenJDK是甲骨文的).

  《ASP.NET Core 高性能系列》是一套如何編寫高性能Web應用技術系列文章,

我們將從.NET 2開始全面升入.其中我們會討論互聯網當今熱門的技術話題:容器、容器編排、服務治理、RPC等

此文是第一篇,用於此系列的開門篇,后面每周會持續發布.

一、Core 2中需要知道的新鮮東西

Core系列有兩個主要產品:

第一個是.NET Core

  它是一個低級別的提供基本庫的框架。 它可以用來編寫控制台應用程序,它也是

更高級別的應用程序框架的基礎。 

第二個是ASP.NET Core

  它是一個用於構建Web的跨平台框架

另外.NET Core中的更改也將適用於ASP.NET Core,因為這是基礎 

二、.NET Core 2的新東西

2.1 API范圍更加廣泛

  .NET Core 2的主要焦點是API范圍的大幅增加,在1.*的基礎上增加了兩倍的API,

而且支持.net standard,您也可以引用.NET Framework程序集而無需重新編譯,

只要程序集中的API已在.NET Core中實現就可以正常工作。這意味着更多的Nuget包可以在.NET Core中工作,

ASP.NET Core Library and Framework 支持情況的一個統計站點:https://ANCLAFS.com(有點跟不上了)

2.2 性能的大幅度提升

.NET Core 2.0中一些更有趣的變化是在原始的.NET FrameworkAPI上性能改進

,已經對許多框架的實現進行了調整了數據結構。 

下面是一些已經看到快速改進的類和方法,已經內存開銷的減少包括:

List<T>
Queue<T>
SortedSet<T>
ConcurrentQueue<T>
Lazy<T>
Enumerable.Concat()
Enumerable.OrderBy()
Enumerable.ToList()
Enumerable.ToArray()
DeflateStream
SHA256
BigInteger
BinaryFormatter
Regex
WebUtility.UrlDecode()
Encoding.UTF8.GetBytes()
Enum.Parse()
DateTime.ToString()
String.IndexOf()
String.StartsWith()
FileStream
Socket
NetworkStream
SslStream
ThreadPool
SpinLock 

  另外,對於.NET Core 2RyuJIT Just In Time編譯器進行了改進。

僅作為一個示例就能說明說明其優秀之處,finally塊現在幾乎與不使用異常一樣高效,

這在沒有拋出異常的正常情況下是有益的。您現在沒有理由不使用tryusing{}塊,以及checked檢查

三、ASP.NET Core 2的新東西 

  ASP.NET Core 2利用了.NET Core 2的所有改進,不僅通過即時編譯處理程序縮短了啟動時間,

涵蓋了增加了輸出緩存,本地及分布式緩存(SQLSERVER,REDIS).

3.1 metapackage

  .NET Core包含了一個新metapackage,所以你只用引用一個NuGet項就可以得到所有的東西,metapackage仍然由單個獨立的包組成,

一個新的包修剪功能(new package-trimming)確保如果您不使用包,那么它的二進制文件將不會包含在您的部署中,

即使您使用metapackage 來引用它。設置Web主機配置也有合理的默認設置。

您無需單獨添加logging, Kestrel, and IISlogging也變得更簡單,因為它是建立的在,你再也沒有任何借口不一開始就使用它

3.2 Razor Pages

  無控制器Razor Pages。 這正是它聽起來的樣子,而且它允許您使用Razor模板編寫頁面。

它類似於Web Pages產品,不必和WebForm混淆。 大家其實覺得是WebForm的卷土重來,個人感覺是滿懷希望的卷土重來,

架構做了更多抽象和思考,不會像之前一樣,帶來如此多的狀態與之相伴.

3.3 新的authentication 模型

  新的 authentication 模型能讓更好地使用了依賴注入, ASP.NETCore Identity 允許你使用OpenID OAuth 2

來為你的API獲取訪問tokens .當然你可以研究Identity Server 4 項目,它提供了相同的功能.

3.4 表單請求自動防偽

  你不必再為表單添加防偽token(防止跨越偽造請求) (之前你不得不添加一個attributePost方法中進行驗證),

現在這一切都是自動的.

3.5性能提升

   ASP.NET Core有一些額外的與.NET Core無關的性能提升:

啟動時間通過即時編譯處理明顯減少,雖然這不是ASP.NET Core 2的新功能;

 output caching依然可用,在1.0時,只有response caching*(簡化了如何設置http header),

1.1 時,添加了memory cache,現在你可以還使用分布式緩存()SQL Server or Redis) 

.NET Standard 2.0

  .NET Standard 是一套正式的 .NET API 規范,目標是在所有 .NET 實現中推出。 推出 .NET Standard 的背后動機是要提高 .NET 生態系統中的一致性。

ECMA 335 持續為 .NET 實現行為建立統一性,但適用於 .NET 庫實現的 .NET 基類庫 (BCL) 沒有類似的規范。

.NET Framework 4.6.1實現了.NET Standard  2.0.

.NET Standard 可實現以下重要情境:

1.為要實現的所有 .NET 實現定義一組統一的、與工作負荷無關的 BCL API

2.使開發人員能夠通過同一組 API 生成可在各種 .NET 實現中使用的可移植庫。

3.減少甚至消除由於 .NET API 方面的原因而對共享源代碼進行的條件性編譯(僅適用於 OS API)。 

五、C# 6.0語言級別的新東西

5.1 屬性可以連帶賦值

public DateTime BirthDay { get; set; } = DateTime.Now.AddYears(-20);

 

5.2 導入靜態類

using static System.Math;

Console.WriteLine($"導入后可直接使用方法: {Pow(4, 2)}");

 

5.3 字符串格式化的變化

Console.WriteLine(string.Format("當前時間:{0}",DateTime.Now.ToString()));

 

5.4 空值運算符

Console.WriteLine(name?.ToString()); // 程序不會報錯,也不會輸出任何值

 

5.5 對象初始化器

可以通過索引的方式進行賦值

IDictionary<int, string> dictNew = new Dictionary<int, string>()
{
       [4] = "first",
       [5] = "second"
};

  

5.6 異常過濾器

int exceptionValue = 10;
try
{
       Int32.Parse("s");
}
catch (Exception e) when (exceptionValue > 1)//滿足條件才進入catch
{
       Console.WriteLine("catch");
}

5.7 nameof表達式

Console.WriteLine(nameof(People));

5.8 在屬性/方法里面使用Lambda表達式

 public void Print() => Console.WriteLine(Name);

 

六、C# 7.0語言級別的新東西

6.1 out變量不需要申明了

  var input = ReadLine();
  if (int.TryParse(input, out var result))
  {

      WriteLine("您輸入的數字是:{0}",result);
  }
  else
  {
      WriteLine("無法解析輸入...");
  }

  

6.2元組

 元組(Tuple)在 .Net 4.0 的時候就有了,但元組也有些缺點,如:

   1)Tuple 會影響代碼的可讀性,因為它的屬性名都是:Item1,Item2.. 。

   2)Tuple 還不夠輕量級,因為它是引用類型(Class)。

   備注:上述所指 Tuple 還不夠輕量級,是從某種意義上來說的或者是一種假設,即假設分配操作非常的多。

 C# 7 中的元組(ValueTuple)解決了上述兩個缺點:

   1)ValueTuple 支持語義上的字段命名。

   2)ValueTuple 是值類型(Struct)。

 

傳統的創建方式

  var tuple = (1, 2);                           // 使用語法糖創建元組

  var tuple2 = ValueTuple.Create(1, 2);         // 使用靜態方法【Create】創建元組 

  var tuple3 = new ValueTuple<int, int>(1, 2);  // 使用 new 運算符創建元組 WriteLine($"first:{tuple.Item1}, second:{tuple.Item2}, 上面三種方式都是等價的。");

//創建給字段命名的元組
// 左邊指定字段名稱
  (int one, int two) tuple = (1, 2);
  WriteLine($"first:{tuple.one}, second:{tuple.two}");
  // 右邊指定字段名稱
  var tuple2 = (one: 1, two: 2);
  WriteLine($"first:{tuple2.one}, second:{tuple2.two}"); 
  // 左右兩邊同時指定字段名稱
  (int one, int two) tuple3 = (first: 1, second: 2);   
 /* 此處會有警告:由於目標類型(xx)已指定了其它名稱,因為忽略元組名稱xxx */
  WriteLine($"first:{tuple3.one}, second:{tuple3.two}");

6.3 解構

6.3.1解構元組 

var (one, two) = GetTuple();
WriteLine($"first:{one}, second:{two}");
static (int, int) GetTuple() {
  return (12, 2);
} 

6.3.2解構可以應用於 .Net 的任意類型,

但需要編寫 Deconstruct 方法成員(實例或擴展)

public void Deconstruct(out type variable1, out type variable2...)
public static void Deconstruct(this type instance, out type variable1, out type variable2...)

 6.4 模式匹配

6.4.1 is 表達式(is expressions

static int GetSum(IEnumerable<object> values)
  {
      var sum = 0;
      if (values == null) return sum;  
      foreach (var item in values)    
{
if (item is short) // C# 7 之前的 is expressions { sum += (short)item; } else if (item is int val) // C# 7 的 is expressions { sum += val; } else if (item is string str && int.TryParse(str, out var result)) // is expressions 和 out variables 結合使用 { sum += result; } else if (item is IEnumerable<object> subList) { sum += GetSum(subList); } } return sum; }  

6.4.2 switch語句

switch (item)
  {
      case type variable1:
          // processing...
          break;
      case type variable2 when predicate:
          // processing...
          break;
      default:
          // processing...
          break;
  }

6.5 Ref locals and returns

static ref int GetLocalRef(int[,] arr, Func<int, bool> func)
  {
      for (int i = 0; i < arr.GetLength(0); i++)
      {
          for (int j = 0; j < arr.GetLength(1); j++)
          {
              if (func(arr[i, j]))
              {
                  return ref arr[i, j];
              }
          }
      }
      throw new InvalidOperationException("Not found");
  }
  int[,] arr = { { 10, 15 }, { 20, 25 } };
  ref var num = ref GetLocalRef(arr, c => c == 20);
  num = 600; 
  Console.WriteLine(arr[1, 0]);  

 總結:雖然 C# 7 中提供了局部引用和引用返回,但為了防止濫用所以也有諸多約束,如:

 1. 你不能將一個值分配給 ref 變量,如:

1   ref int num = 10;   // error:無法使用值初始化按引用變量

 2. 你不能返回一個生存期不超過方法作用域的變量引用,如:

1 public ref int GetLocalRef(int num) => ref num;   // error: 無法按引用返回參數,因為它不是 ref out 參數

 3. ref 不能修飾 “屬性” 和 “索引器”。 

1   var list = new List<int>();2   ref var n = ref list.Count;  // error: 屬性或索引器不能作為 out ref 參數傳遞

 原理解析:非常簡單就是指針傳遞,並且個人覺得此語法的使用場景非常有限,都是用來處理大對象的,目的是減少GC提高性能。

6.5 局部函數

static IEnumerable<char> GetCharList(string str)
   {
       if (IsNullOrWhiteSpace(str))

           throw new ArgumentNullException(nameof(str));

       return GetList();   

       IEnumerable<char> GetList()
       {
           for (int i = 0; i < str.Length; i++)
           {
               yield return str[i];
           }
       }
   } 

6.6. 擴展異步返回類型(Generalized async return types 

 以前異步的返回類型必須是:Task、Task<T>、void,現在 C# 7 中新增了一種類型:ValueTask<T>,如下所示:

  public async ValueTask<int> Func()
  {
     await Task.Delay(3000);
     return 100;
  }

  總結:ValueTask<T> 與 ValueTuple 非常相似,所以就不列舉: ValueTask<T> 與 Task 之間的異同了,\但它們都是為了優化特定場景性能而

 新增的類型。  使用 ValueTask<T> 則需要導入:

Install - Package System.Threading.Tasks.Extensions

6.7. 數字文本語法的改進(Numeric literal syntax improvements 

 C# 7 還包含兩個新特性:二進制文字、數字分隔符,如下所示:

var one = 0b0001;
var sixteen = 0b0001_0000;
long salary = 1000_000_000;
decimal pi = 3.141_592_653_589m;

 注:二進制文本是以0b(零b)開頭,字母不區分大小寫;數字分隔符只有三個地方不能寫:開頭,結尾,小數點前后。

 總結:二進制文本,數字分隔符 可使常量值更具可讀性。

七、異步的優化

  盡管如此,異步方法可以返回的內容一些小改進,但是可以在某些情況下提供巨大的性能提升。 你不再需要返回一個Task,如果值已經可用這可以減少開銷,使用async方法來創建Task對象。

八、總結

  在這個介紹性章節中,您看到了一個簡短而高級的摘要,與先前版本相比,.NET Core 2和ASP.NET Core 2眾多變化。

現在,你也知道了.NET Standard 2及其用途。我們展示了C#6和C#7中可用的一些新功能的例子。

這些可能非常有用的是讓你用更少的東西編寫更多東西,並使你的代碼更易讀和更容易維護。

       《ASP.NET Core 高性能系列》這是一本關於一般Web應用程序性能改進的文章,而且很多無視語言或框架的知識。

  下一章中,您將了解性能如何重要,並了解嶄新的新.NET Core開發棧, 我們還將看到可用的工具,並了解用圖表展示硬件性能。

 

額外推薦Span Memory相關文章

https://www.cnblogs.com/uoyo/p/12207148.html

.net core中的System.Buffers名字空間

https://www.cnblogs.com/TianFang/p/9193881.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM