主頁 > .NET開發 > C#性能優化雜七雜八的總結

C#性能優化雜七雜八的總結

2020-09-21 18:59:43 .NET開發

C#性能優化總結

1. C#語言方面

 

1.1 垃圾回收

垃圾回收解放了手工管理物件的作業,提高了程式的健壯性,但副作用就是程式代碼可能對于物件創建變得隨意,

1.1.1 避免不必要的物件創建

由于垃圾回收的代價較高,所以C#程式開發要遵循的一個基本原則就是避免不必要的物件創建,以下列舉一些常見的情形,

1.1.1.1 避免回圈創建物件 ★

如果物件并不會隨每次回圈而改變狀態,那么在回圈中反復創建物件將帶來性能損耗,高效的做法是將物件提到回圈外面創建,

1.1.1.2 在需要邏輯分支中創建物件

如果物件只在某些邏輯分支中才被用到,那么應只在該邏輯分支中創建物件,

1.1.1.3 使用常量避免創建物件

程式中不應出現如 new Decimal(0) 之類的代碼,這會導致小物件頻繁創建及回收,正確的做法是使用Decimal.Zero常量,我們有設計自己的類時,也可以學習這個設計手法,應用到類似的場景中,

1.1.1.4 使用StringBuilder做字串連接

 

1.1.2 不要使用空解構式 ★

如果類包含解構式,由創建物件時會在 Finalize 佇列中添加物件的參考,以保證當物件無法可達時,仍然可以呼叫到 Finalize 方法,垃圾回收器在運行期間,會啟動一個低優先級的執行緒處理該佇列,相比之下,沒有解構式的物件就沒有這些消耗,如果解構式為空,這個消耗就毫無意 義,只會導致性能降低!因此,不要使用空的解構式,

在實際情況中,許多曾在解構式中包含處理代碼,但后來因為種種原因被注釋掉或者洗掉掉了,只留下一個空殼,此時應注意把解構式本身注釋掉或洗掉掉,

1.1.3 實作 IDisposable 介面

垃圾回收事實上只支持托管內在的回收,對于其他的非托管資源,例如 Window GDI 句柄或資料庫連接,在解構式中釋放這些資源有很大問題,原因是垃圾回收依賴于內在緊張的情況,雖然資料庫連接可能已瀕臨耗盡,但如果記憶體還很充足的話, 垃圾回收是不會運行的,

C#的 IDisposable 介面是一種顯式釋放資源的機制,通過提供 using 陳述句,還簡化了使用方式(編譯器自動生成 try ... finally 塊,并在 finally 塊中呼叫 Dispose 方法),對于申請非托管資源物件,應為其實作 IDisposable 介面,以保證資源一旦超出 using 陳述句范圍,即得到及時釋放,這對于構造健壯且性能優良的程式非常有意義!

為防止物件的 Dispose 方法不被呼叫的情況發生,一般還要提供解構式,兩者呼叫一個處理資源釋放的公共方法,同時,Dispose 方法應呼叫 System.GC.SuppressFinalize(this),告訴垃圾回收器無需再處理 Finalize 方法了,

1.2 String 操作

1.2.1 使用 StringBuilder 做字串連接

String 是不變類,使用 + 操作連接字串將會導致創建一個新的字串,如果字串連接次數不是固定的,例如在一個回圈中,則應該使用 StringBuilder 類來做字串連接作業,因為 StringBuilder 內部有一個 StringBuffer ,連接操作不會每次分配新的字串空間,只有當連接后的字串超出 Buffer 大小時,才會申請新的 Buffer 空間,典型代碼如下:

 

 StringBuilder sb = new StringBuilder( 256 );

 

 for ( int i = 0 ; i < Results.Count; i ++ )

 

 {

 

 sb.Append (Results[i]);

 

}

 

如果連接次數是固定的并且只有幾次,此時應該直接用 + 號連接,保持程式簡潔易讀,實際上,編譯器已經做了優化,會依據加號次數呼叫不同引數個數的 String.Concat 方法,例如:

String str = str1 + str2 + str3 + str4;

會被編譯為 String.Concat(str1, str2, str3, str4),該方法內部會計算總的 String 長度,僅分配一次,并不會如通常想象的那樣分配三次,作為一個經驗值,當字串連接操作達到 10 次以上時,則應該使用 StringBuilder,

這里有一個細節應注意:StringBuilder 內部 Buffer 的預設值為 16 ,這個值實在太小,按 StringBuilder 的使用場景,Buffer 肯定得重新分配,經驗值一般用 256 作為 Buffer 的初值,當然,如果能計算出最終生成字串長度的話,則應該按這個值來設定 Buffer 的初值,使用 new StringBuilder(256) 就將 Buffer 的初始長度設為了256,

1.2.2 避免不必要的呼叫 ToUpper 或 ToLower 方法

String是不變類,呼叫ToUpper或ToLower方法都會導致創建一個新的字串,如果被頻繁呼叫,將導致頻繁創建字串物件,這違背了前面講到的“避免頻繁創建物件”這一基本原則,

例如,bool.Parse方法本身已經是忽略大小寫的,呼叫時不要呼叫ToLower方法,

另一個非常普遍的場景是字串比較,高效的做法是使用 Compare 方法,這個方法可以做大小寫忽略的比較,并且不會創建新字串,

還有一種情況是使用 HashTable 的時候,有時候無法保證傳遞 key 的大小寫是否符合預期,往往會把 key 強制轉換到大寫或小寫方法,實際上 HashTable 有不同的構造形式,完全支持采用忽略大小寫的 key: new HashTable(StringComparer.OrdinalIgnoreCase),

1.2.3 最快的空串比較方法

將String物件的Length屬性與0比較是最快的方法:if (str.Length == 0)

其次是與String.Empty常量或空串比較:if (str == String.Empty)或if (str == "")

注:C#在編譯時會將程式集中宣告的所有字串常量放到保留池中(intern pool),相同常量不會重復分配,

1.3 多執行緒

1.3.1 執行緒同步

線 程同步是撰寫多執行緒程式需要首先考慮問題,C#為同步提供了 Monitor、Mutex、AutoResetEvent 和 ManualResetEvent 物件來分別包裝 Win32 的臨界區、互斥物件和事件物件這幾種基礎的同步機制,C#還提供了一個lock陳述句,方便使用,編譯器會自動生成適當的 Monitor.Enter 和 Monitor.Exit 呼叫,

1.3.1.1 同步粒度

同步粒度可以是整個方法,也可以是方法中某一段代碼,為方法指定 MethodImplOptions.Synchronized 屬性將標記對整個方法同步,例如:

 

 [MethodImpl(MethodImplOptions.Synchronized)]

 

 public static SerialManager GetInstance()

 

 {

 

 if (instance == null )

 

 {

 

 instance = new SerialManager();

 

 }

 

 return instance;

 

}

通常情況下,應減小同步的范圍,使系統獲得更好的性能,簡單將整個方法標記為同步不是一個好主意,除非能確定方法中的每個代碼都需要受同步保護,

1.3.1.2 同步策略

使用 lock 進行同步,同步物件可以選擇 Type、this 或為同步目的專門構造的成員變數,

避免鎖定Type★

鎖定Type物件會影響同一行程中所有AppDomain該型別的所有實體,這不僅可能導致嚴重的性能問題,還可能導致一些無法預期的行為,這是一個很不 好的習慣,即便對于一個只包含static方法的型別,也應額外構造一個static的成員變數,讓此成員變數作為鎖定物件,

避免鎖定 this

鎖定 this 會影響該實體的所有方法,假設物件 obj 有 A 和 B 兩個方法,其中 A 方法使用 lock(this) 對方法中的某段代碼設定同步保護,現在,因為某種原因,B 方法也開始使用 lock(this) 來設定同步保護了,并且可能為了完全不同的目的,這樣,A 方法就被干擾了,其行為可能無法預知,所以,作為一種良好的習慣,建議避免使用 lock(this) 這種方式,

使用為同步目的專門構造的成員變數

這是推薦的做法,方式就是 new 一個 object 物件, 該物件僅僅用于同步目的,

如果有多個方法都需要同步,并且有不同的目的,那么就可以為些分別建立幾個同步成員變數,

1.3.1.4 集合同步

C#為各種集合型別提供了兩種方便的同步機制:Synchronized 包裝器和 SyncRoot 屬性,

 

 // Creates and initializes a new ArrayList

 

 ArrayList myAL = new ArrayList();

 

myAL.Add( " The " );

 

myAL.Add( " quick " );

 

myAL.Add( " brown " );

 

myAL.Add( " fox " );

 

 

 

 // Creates a synchronized wrapper around the ArrayList

 

 ArrayList mySyncdAL = ArrayList.Synchronized(myAL);

呼叫 Synchronized 方法會回傳一個可保證所有操作都是執行緒安全的相同集合物件,考慮 mySyncdAL[0] = mySyncdAL[0] + "test" 這一陳述句,讀和寫一共要用到兩個鎖,一般講,效率不高,推薦使用 SyncRoot 屬性,可以做比較精細的控制,

1.3.2 使用 ThreadStatic 替代 NameDataSlot ★

存 取 NameDataSlot 的 Thread.GetData 和 Thread.SetData 方法需要執行緒同步,涉及兩個鎖:一個是 LocalDataStore.SetData 方法需要在 AppDomain 一級加鎖,另一個是 ThreadNative.GetDomainLocalStore 方法需要在 Process 一級加鎖,如果一些底層的基礎服務使用了 NameDataSlot,將導致系統出現嚴重的伸縮性問題,

規避這個問題的方法是使用 ThreadStatic 變數,示例如下:

 

 public sealed class InvokeContext

 

 {

 

 [ThreadStatic]

 

 private static InvokeContext current;

 

 private Hashtable maps = new Hashtable();

 

}

1.3.3 多執行緒編程技巧

1.3.3.1 使用 Double Check 技術創建物件

 

 internal IDictionary KeyTable

 

 {

 

 get

 

 {

 

 if ( this ._keyTable == null )

 

 {

 

 lock ( base ._lock)

 

 {

 

 if ( this ._keyTable == null )

 

 {

 

 this ._keyTable = new Hashtable();

 

 }

 

 }

 

 }

 

 return this ._keyTable;

 

 }

 

}

創建單例物件是很常見的一種編程情況,一般在 lock 陳述句后就會直接創建物件了,但這不夠安全,因為在 lock 鎖定物件之前,可能已經有多個執行緒進入到了第一個 if 陳述句中,如果不加第二個 if 陳述句,則單例物件會被重復創建,新的實體替代掉舊的實體,如果單例物件中已有資料不允許被破壞或者別的什么原因,則應考慮使用 Double Check 技術,

1.4 型別系統

1.4.1 避免無意義的變數初始化動作

CLR保證所有物件在訪問前已初始化,其做法是將分配的記憶體清零,因此,不需要將變數重新初始化為0、false或null,

需要注意的是:方法中的區域變數不是從堆而是從堆疊上分配,所以C#不會做清零作業,如果使用了未賦值的區域變數,編譯期間即會報警,不要因為有這個印象而對所有類的成員變數也做賦值動作,兩者的機理完全不同!

1.4.2 ValueType 和 ReferenceType

1.4.2.1 以參考方式傳遞值型別引數

值型別從呼叫堆疊分配,參考型別從托管堆分配,當值型別用作方法引數時,默認會進行引數值復制,這抵消了值型別分配效率上的優勢,作為一項基本技巧,以參考方式傳遞值型別引數可以提高性能,

1.4.2.2 為 ValueType 提供 Equals 方法

.net 默認實作的 ValueType.Equals 方法使用了反射技術,依靠反射來獲得所有成員變數值做比較,這個效率極低,如果我們撰寫的值物件其 Equals 方法要被用到(例如將值物件放到 HashTable 中),那么就應該多載 Equals 方法,

 

 public struct Rectangle

 

 {

 

 public double Length;

 

 public double Breadth;

 

 public override bool Equals ( object ob)

 

 {

 

 if (ob is Rectangle)

 

 return Equels ((Rectangle)ob))

 

 else

 

 return false ;

 

 }

 

 private bool Equals (Rectangle rect)

 

 {

 

 return this .Length == rect.Length && this .Breadth == rect.Breach;

 

 }

 

}

1.4.2.3 避免裝箱和拆箱

C#可以在值型別和參考型別之間自動轉換,方法是裝箱和拆箱,裝箱需要從堆上分配物件并拷貝值,有一定性能消耗,如果這一程序發生在回圈中或是作為底層方法被頻繁呼叫,則應該警惕累計的效應,

一種經常的情形出現在使用集合型別時,例如:

 

 ArrayList al = new ArrayList();

 

 for ( int i = 0 ; i < 1000 ; i ++ )

 

 {

 

 al.Add(i); // Implicitly boxed because Add() takes an object

 

 }

 

 int f = ( int )al[ 0 ]; // The element is unboxed

1.5 例外處理

例外也是現代語言的典型特征,與傳統檢查錯誤碼的方式相比,例外是強制性的(不依賴于是否忘記了撰寫檢查錯誤碼的代碼)、強型別的、并帶有豐富的例外資訊(例如呼叫堆疊),

1.5.1 不要吃掉例外★

關于例外處理的最重要原則就是:不要吃掉例外,這個問題與性能無關,但對于撰寫健壯和易于排錯的程式非常重要,這個原則換一種說法,就是不要捕獲那些你不能處理的例外,

吃掉例外是極不好的習慣,因為你消除了解決問題的線索,一旦出現錯誤,定位問題將非常困難,除了這種完全吃掉例外的方式外,只將例外資訊寫入日志檔案但并不做更多處理的做法也同樣不妥,

1.5.2 不要吃掉例外資訊★

有些代碼雖然拋出了例外,但卻把例外資訊吃掉了,

為例外披露詳盡的資訊是程式員的職責所在,如果不能在保留原始例外資訊含義的前提下附加更豐富和更人性化的內容,那么讓原始的例外資訊直接展示也要強得多,千萬不要吃掉例外,

1.5.3 避免不必要的拋出例外

拋出例外和捕獲例外屬于消耗比較大的操作,在可能的情況下,應通過完善程式邏輯避免拋出不必要不必要的例外,與此相關的一個傾向是利用例外來控制處理邏輯,盡管對于極少數的情況,這可能獲得更為優雅的解決方案,但通常而言應該避免,

1.5.4 避免不必要的重新拋出例外

如果是為了包裝例外的目的(即加入更多資訊后包裝成新例外),那么是合理的,但是有不少代碼,捕獲例外沒有做任何處理就再次拋出,這將無謂地增加一次捕獲例外和拋出例外的消耗,對性能有傷害,

1.6 反射

反射是一項很基礎的技術,它將編譯期間的靜態系結轉換為延遲到運行期間的動態系結,在很多場景下(特別是類框架的設計),可以獲得靈活易于擴展的架構,但帶來的問題是與靜態系結相比,動態系結會對性能造成較大的傷害,

1.6.1 反射分類

type comparison :型別判斷,主要包括 is 和 typeof 兩個運算子及物件實體上的 GetType 呼叫,這是最輕型的消耗,可以無需考慮優化問題,注意 typeof 運算子比物件實體上的 GetType 方法要快,只要可能則優先使用 typeof 運算子,

member enumeration : 成員列舉,用于訪問反射相關的元資料資訊,例如Assembly.GetModule、Module.GetType、Type物件上的 IsInterface、IsPublic、GetMethod、GetMethods、GetProperty、GetProperties、 GetConstructor呼叫等,盡管元資料都會被CLR快取,但部分方法的呼叫消耗仍非常大,不過這類方法呼叫頻度不會很高,所以總體看性能損失程 度中等,

member invocation:成員呼叫,包括動態創建物件及動態呼叫物件方法,主要有Activator.CreateInstance、Type.InvokeMember等,

1.6.2 動態創建物件

C#主要支持 5 種動態創建物件的方式:

1. Type.InvokeMember

2. ContructorInfo.Invoke

3. Activator.CreateInstance(Type)

4. Activator.CreateInstance(assemblyName, typeName)

5. Assembly.CreateInstance(typeName)

最快的是方式 3 ,與 Direct Create 的差異在一個數量級之內,約慢 7 倍的水平,其他方式,至少在 40 倍以上,最慢的是方式 4 ,要慢三個數量級,

1.6.3 動態方法呼叫

方法呼叫分為編譯期的早期系結和運行期的動態系結兩種,稱為Early-Bound Invocation和Late-Bound Invocation,Early-Bound Invocation可細分為Direct-call、Interface-call和Delegate-call,Late-Bound Invocation主要有Type.InvokeMember和MethodBase.Invoke,還可以通過使用LCG(Lightweight Code Generation)技術生成IL代碼來實作動態呼叫,

從測驗結果看,相比Direct Call,Type.InvokeMember要接近慢三個數量級;MethodBase.Invoke雖然比Type.InvokeMember要快三 倍,但比Direct Call仍慢270倍左右,可見動態方法呼叫的性能是非常低下的,我們的建議是:除非要滿足特定的需求,否則不要使用!

1.6.4 推薦的使用原則

模式

1. 如果可能,則避免使用反射和動態系結

2. 使用介面呼叫方式將動態系結改造為早期系結

3. 使用Activator.CreateInstance(Type)方式動態創建物件

4. 使用typeof運算子代替GetType呼叫

反模式

1. 在已獲得Type的情況下,卻使用Assembly.CreateInstance(type.FullName)

1.7 基本代碼技巧

這里描述一些應用場景下,可以提高性能的基本代碼技巧,對處于關鍵路徑的代碼,進行這類的優化還是很有意義的,普通代碼可以不做要求,但養成一種好的習慣也是有意義的,

1.7.1 回圈寫法

可以把回圈的判斷條件用區域變數記錄下來,區域變數往往被編譯器優化為直接使用暫存器,相對于普通從堆或堆疊中分配的變數速度快,如果訪問的是復雜計算屬性 的話,提升效果將更明顯,for (int i = 0, j = collection.GetIndexOf(item); i < j; i++)

需要說明的是:這種寫法對于CLR集合類的Count屬性沒有意義,原因是編譯器已經按這種方式做了特別的優化,

1.7.2 拼裝字串

拼裝好之后再洗掉是很低效的寫法,有些方法其回圈長度在大部分情況下為1,這種寫法的低效就更為明顯了:

 

 public static string ToString(MetadataKey entityKey)

 

 {

 

 string str = "" ;

 

 object [] vals = entityKey.values;

 

 for ( int i = 0 ; i < vals.Length; i ++ )

 

 {

 

 str += " , " + vals[i].ToString();

 

 }

 

 return str == "" ? "" : str.Remove( 0 , 1 );

 

}

推薦下面的寫法:

 

 if (str.Length == 0 )

 

 str = vals[i].ToString();

 

 else

 

 str += " , " + vals[i].ToString();

其實這種寫法非常自然,而且效率很高,完全不需要用個Remove方法繞來繞去,

1.7.3 避免兩次檢索集合元素

獲取集合元素時,有時需要檢查元素是否存在,通常的做法是先呼叫ContainsKey(或Contains)方法,然后再獲取集合元素,這種寫法非常符合邏輯,

但如果考慮效率,可以先直接獲取物件,然后判斷物件是否為null來確定元素是否存在,對于Hashtable,這可以節省一次GetHashCode呼叫和n次Equals比較,

如下面的示例:

 

 public IData GetItemByID(Guid id)

 

 {

 

 IData data1 = null ;

 

 if ( this .idTable.ContainsKey(id.ToString())

 

 {

 

 data1 = this .idTable[id.ToString()] as IData;

 

 }

 

 return data1;

 

}

其實完全可用一行代碼完成:return this.idTable[id] as IData;

1.7.4 避免兩次型別轉換

考慮如下示例,其中包含了兩處型別轉換:

 

 if (obj is SomeType)

 

 {

 

 SomeType st = (SomeType)obj;

 

 st.SomeTypeMethod();

 

}

效率更高的做法如下:

 

 SomeType st = obj as SomeType;

 

 if (st != null )

 

 {

 

 st.SomeTypeMethod();

 

}

1.8 Hashtable

Hashtable是一種使用非常頻繁的基礎集合型別,需要理解影響Hashtable的效率有兩個因素:一是散列碼(GetHashCode方法),二 是等值比較(Equals方法),Hashtable首先使用鍵的散列碼將物件分布到不同的存盤桶中,隨后在該特定的存盤桶中使用鍵的Equals方法進 行查找,

良好的散列碼是第一位的因素,最理想的情況是每個不同的鍵都有不同的散列碼,Equals方法也很重要,因為散列只需要做一次,而存盤桶中查找鍵可能需要做多次,從實際經驗看,使用Hashtable時,Equals方法的消耗一般會占到一半以上,

System.Object類提供了默認的GetHashCode實作,使用物件在記憶體中的地址作為散列碼,我們遇到過一個用Hashtable來快取對 象的例子,每次根據傳遞的OQL運算式構造出一個ExpressionList物件,再呼叫QueryCompiler的方法編譯得到 CompiledQuery物件,以ExpressionList物件和CompiledQuery物件作為鍵值對存盤到Hashtable中, ExpressionList物件沒有多載GetHashCode實作,其超類ArrayList也沒有,這樣最后用的就是System.Object類 的GetHashCode實作,由于ExpressionList物件會每次構造,因此它的HashCode每次都不同,所以這個 CompiledQueryCache根本就沒有起到預想的作用,這個小小的疏漏帶來了重大的性能問題,由于決議OQL運算式頻繁發生,導致 CompiledQueryCache不斷增長,造成服務器記憶體泄漏!解決這個問題的最簡單方法就是提供一個常量實作,例如讓散列碼為常量0,雖然這會導 致所有物件匯聚到同一個存盤桶中,效率不高,但至少可以解決掉記憶體泄漏問題,當然,最侄訓是會實作一個高效的GetHashCode方法的,

1.9 大批量資料操作

當需要對資料庫進行大批量資料操作的時候,推薦使用分批操作的功能,比如一百萬條資料將其分為每一萬條資料進行資料庫操作,而不是每條資料回圈去進行操作,

查詢 - 分批查詢對資料庫的壓力較小,如果那一張表在這個時候可能其他地方也更新或新增 可能需要考慮增加with(NOLOCK) ,當然如果是EF 就套上讀未提交的事務(會變卡) 也可以讓查詢不加鎖,

洗掉 - 首推根據主健進行洗掉,因為資料庫根據主鍵的索引查找和洗掉資料非常快,當然分批更好,

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/99121.html

標籤:C#

上一篇:OpenCvSharp+ZXing實作多個DataMatrix決議

下一篇:C#快取初步學習

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more