當前位置: 妍妍網 > 碼農

.NET9 Linux-x64下Console.WriteLine原理

2024-02-23碼農

點選上方 藍字 江湖評談 設為關註




1.前言

之前聊過Windows下面Console.WriteLine的執行過程 本篇看下它在Linu-x64下面最新.NET9執行過程

2.受控代碼:

.NET裏面流讀寫數據一般都是透過 StreamReader StreamWriter這兩個類 操作。 它們名稱空間在: System.IO。 托管庫: System.Runtime.dll,比如以下簡單的操作小例子:

using (StreamWriter writer = File.CreateText("newfile.txt")){await writer.WriteLineAsync("First line of example");await writer.WriteLineAsync("and second line");}

StreamWriter和StreamReader分別衍生自TextWriter和TextReader。Console.WriteLine打印出的字串,則是在CLR柯瑞面直接透過TextWriter寫入到的數據流/裝置。

比如例子:

staticvoidMain(string[] args){ Console.WriteLine("Call Main");}

Console.WriteLine會呼叫Out.EnsureInitialized函式, Out即是TextWriter型別,程式碼如下:

源碼地址:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Console/src/System/Console.cspublicstatic TextWriter Out {get {static TextWriter EnsureInitialized() {lock (s_syncObject) {if (s_out == null) { Volatile.Write(ref s_out, CreateOutputWriter(ConsolePal.OpenStandardOutput())); }return s_out; } } } }

Ensu reInitialized函式裏面呼叫了Volatile.Write函式, Volatile.W rite函式 的意思是,把參數二的值寫入到參數一欄位裏面去。這裏的解釋就是 把CreateOutputWr iter(ConsolePa l.OpenStandardOutput())返回的值寫入s_out欄位,s_out也是TextWriter型別。

這裏看下CreateOutputWriter(ConsolePal.OpenStandardOutput())返回的值是啥。 CreateOutputWriter函式如下:

源碼地址:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Console/src/System/Console.csprivatestatic TextWriter CreateOutputWriter(Stream outputStream){return outputStream == Stream.Null ? TextWriter.Null : TextWriter.Synchronized(new StreamWriter( stream: outputStream, encoding: OutputEncoding.RemovePreamble(), bufferSize: WriteBufferSize, leaveOpen: true) { AutoFlush = true });}

可以看到CreateOutputWriter返回的依舊是TextWriter,也就是說Volatile.Write把流數據寫入到流數據,然後從裝置上打印出來。

這裏寫入的流數據值到底是什麽呢?繼續看ConsolePal.OpenStandardOutput()函式,它返回的是Stream型別。

源碼地址:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Console/src/System/ConsolePal.Unix.cspublicstatic Stream OpenStandardOutput(){returnnew UnixConsoleStream(Interop.CheckIo(Interop.Sys.Dup(Interop.Sys.FileDescriptors.STDOUT_FILENO)), FileAccess.Write);}

這裏是Linux/Unix下面的操作,OpenStandardOutput裏面例項化了一個UnixConsoleStream類,UnixConsoleStream的建構函式裏面,第一個參數是Interop.CheckIo(Interop.Sys.Dup(Interop.Sys.FileDescriptors.STDOUT_FILENO))。Interop.Sys.Dup是Linux下面進行檔表項操作的函式 。CheckIo則是個檢查函式,此處可以忽略。

舉個例子,一般的來說Linux下面在終端打印一個hello World通常透過printf("hello Word")

printf -> stdout(標準輸出) -> Dup(STDOUT_FILENO) ->終端輸出

可見Linux下面是透過Dup函式傳遞參數STDOUT_FILENO進行終端操作的,UnixConsoleStream第二個參數是FileAccess.Write,表示寫入字串。然後把這個Stream封 裝後返回,透過Volatile.Write寫入到終端流裏面打印出來。

那麽其實很清晰了,流程大致如下:

Console.WriteLine->Out.EnsureInitialized-ConsolePal.OpenStandardOutput() -Interop.Sys.Dup->Volatile.Write

這裏面有很多可以討論和深入的細節點,了解更多可以加入我的 ,一起學習,一起進步。

往期精彩回顧