.net core 并发下的线程安全问题
抱歉,其實內容并不如題!!!
背景(寫測試demo所出現的異常,供大家學習與拍磚):
.net core webapi項目,做了一個授權的filter(真正的生產項目的話,JWT很棒),單個接口測試沒有問題,當用前端在同一個頁面調用多個接口的時候,運行服務,打開頁面,然后……Exceptions……(真正的開發中大家應該也會遇到)
異常1:An?attempt?was?made?to?use?the?context?while?it?is?being?configured.?A?DbContext?instance?cannot?be?used?inside?OnConfiguring?since?it?is?still?being?configured?at?this?point.?This?can?happen?if?a?second?operation?is?started?on?this?context?before?a?previous?operation?completed.?Any?instance?members?are?not?guaranteed?to?be?thread?safe.
異常2:A?second?operation?started?on?this?context?before?a?previous?operation?completed.?Any?instance?members?are?not?guaranteed?to?be?thread?safe.
異常3:Invalid?attempt?to?call?Read?when?reader?is?closed.
異常4:Unable?to?cast?object?of?type?'System.Data.ProviderBase.DbConnectionClosedConnecting'?to?type?'System.Data.SqlClient.SqlInternalConnectionTds'.
異常5:Object?reference?not?set?to?an?instance?of?an?object.
異常6:不允許啟動新事務,因為有其他線程正在該會話中運行。
異常7:An?error?occurred?while?updating?the?entries.?See?the?inner?exception?for?details.
嘗試運行了N多遍,嗯,挺不穩定的(代碼垃圾!),那看看異常吧
一看很容易理解:在前一個操作完成之前,在此上下文中啟動第二個操作。任何實例成員都不能保證是線程安全的。就是說,我在用這個上下文的時候,你來搶個屁……
這個可能發生在并發的情況下,同時使用了同一個上下文……那么打開一個頁面,為什么會同時使用同一個上下文呢?好吧,在這里要負荊請罪了(可以說是自己的問題)
我在Filter里面有查詢,用到數據庫上下文<DbContext>?。罪過咯,直接想在Filter里面過濾黑名單,所以查了數據庫(這個業務是不合理的,這是一個作死的行為,請謹慎看待,這里做學習討論之用)。
public class?AuthFilterAttribute?:?ActionFilterAttribute{
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
.....
//判斷是否在黑名單內
var blackList = _app.GetBlackList();
......
}
}
這里為什么用?ActionFilterAttribute??是因為測試的時候要監測一下接口運行的整個過程,So……
然后還有一些錯是:對象引用未設置為對象的實例。這個錯誤太常見,不就是對象為Null了嗎?但是,未實例化對象在業務邏輯上的情況太多了。我的應該有:
1、沒有獲取到當前對象,這是.net?core,不是.net,不是因為沒有new對象。是注入中沒有注入成功,獲取注入后,沒有獲取到。(但我本來運行的好好的,是因為一下是打開對接的頁面才發生的問題,可以排除了)
2、本來已經實例的對象被回收了……(這可能性嘛……有一定的可能,但發生在哪呢?)
找啊找,其實方向有了,但是自己卻沒想起來……
其實如果不確定的話,倒是可以先找找別人是怎么說的(不是為了裝X,找開發上的問題我是推薦?github?和?stackoverflow?的,大部分的問題都可以找到):
(1)異常 1?還有同樣?一條搜索結果
?
(2)異常 2
?
雖然以上找的不一定是真正的答案,至少提供了一個方向,并且你至少可以嘗試性地去解決一下。這里提供的方向其實很明確:
1、是否應該使用?Scoped?和?Transient?的,你卻使用了?Singleton;
2、多線程中使用了?async?卻沒有配對的使用?await;
至少我找到的關鍵點是這兩個。
那怎么找到并解決這個問題呢,.net?core都是注入的,當然?AuthFilterAttribute?也是注入的。跑到?Startup一看,很明顯,問題出在哪里了?--?單例!本應該是Scoped模式的,卻用了單例。
那就將?AuthFilterAttribute?換一種注入模式就行啦。
?
改為
?
我使用的是Filter,Filter有自己的生命周期,去確認一下:Filter的官方文檔
看到一張圖!!!(當然你也可以細細研讀一下這個文檔)如下:
這還不明顯?!!!
Filter會被回收的!!!這同樣解釋了?異常3、4、5、6、7所發生的原因。
OK,問題已經解決了,這是在開發中遇到的問題,可以說是涉及到.net?core?本身的運行機制。
我算是一個應用型的程序員,喜歡在應用中學習底層的東西。那么接下來當然就可以擴展?Singleton、Scoped?和?Transient?等知識了。?
如不喜,請拍!
原文地址:https://www.cnblogs.com/Vam8023/p/10656777.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?
總結
以上是生活随笔為你收集整理的.net core 并发下的线程安全问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DI是实现面向切面和面向抽象的前提
- 下一篇: C#并行编程(2):.NET线程池