![](/img/trans.png)
[英]WeakReference behaves differently between .Net Framework and .Net Core
[英]Entity Framework Core - Query ran simultaneously behaves differently on different environment
問題:我注意到同時啟動的實體框架調用的處理時間越來越長。 程序是.NET Core 2.2,帶EF 2.2
以下是演示該行為的日志示例:
並且在第 30 次查詢時最多持續 10 秒。
調查:
為了重現和測試這一點,我創建了一個簡單的可執行文件,它將並行調用方法 Test() 20 次,Test() 從 ServiceProvider 獲取作用域上下文,並對數據庫進行查詢。 我已經執行了幾次,並顯示了每個設置的 3 個結果的屏幕截圖。 注意:Query() 方法在 20 次測試之前運行一次,允許 EF 生成查詢緩存
private async Task Test()
{
List<Task> tasks = new List<Task>();
// Populate the queue.
for (int i = 0; i < 10000; i++)
{
cq.Enqueue(i);
}
Query();
Thread.Sleep(1000);
Query();
Thread.Sleep(1000);
for (int i = 0; i < 20; i++)
{
tasks.Add(Task.Run(() => Query()));
}
await Task.WhenAll(tasks);
}
private async Task Query()
{
cq.TryDequeue(out int id);
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: started");
using (var serviceScope = _serviceProvider.CreateScope())
{
var watch = new Stopwatch();
var ctx = serviceScope.ServiceProvider.GetService<Core.Models.MyContext>();
watch.Start();
var quoteLineJob = await ctx.QuoteLineJobs
.FirstOrDefaultAsync(o => o.Id == id);
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
}
}
我無法理解結果,希望有人能提出一個假設:
加載時間越來越長
但是,訪問相同的數據庫時,結果要慢得多。
結果與開發人員的機器非常相似,但是,它有 50% 的機會隨機運行(參見第三個結果)而不是增量
我想補充一點,查看 SQL Server Profiler,對於所有設置,所有同時查詢的讀取查詢需要 0 毫秒。
好像這並不令人困惑,當我在 localhost 上嘗試相同的測試時:
這里的結果是隨機的,不遞增
同樣,加載時間是隨機的,不會增加
有沒有人看到一些模式和建議,為什么 Entity Framework 會這樣?
我的第一個建議是確定原因是 EF 還是您的服務包裝器,具體取決於實現方式。 改為將此測試更改為並檢查不同環境的性能:
var watch = new Stopwatch();
watch.Start();
using (var ctx = new YourAppDbContext(ConnectionString))
{
var quoteLineJob = await ctx.QuoteLineJobs
.FirstOrDefaultAsync(o => o.Id == id);
}
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
如果這表現得更可預測,那么您的上下文 scope 或 DbContext 的提供者就會出現問題。 (不太可能,但沒有看到代碼,有可能)
如果它仍然有些可變,這可能是並行化的症狀。 在執行異步代碼時,等待的方法將設置恢復執行點並釋放正在執行的線程。 .Net 將響應恢復線程操作的請求。 鑒於這些操作已經被並行化到任務中,一項測試是同步進行 EF 調用以評估是否恢復了更可預測的性能。 服務器的核心數和整體負載情況可能會極大地影響 20 個或更多並行化的執行方式。
var watch = new Stopwatch();
watch.Start();
using (var ctx = new YourAppDbContext(ConnectionString))
{
var quoteLineJob = ctx.QuoteLineJobs
.FirstOrDefault(o => o.Id == id);
}
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
同樣,這只是為了幫助確定性能難題的潛在原因。 async
/ await
不等於更好的性能,它們使單個操作變慢,但使整個服務器對處理更多請求的響應更快,而無需等待較慢或高頻任務完成后再接收請求。 線程之間的上下文切換將意味着每個任務的運行速度都會變慢,並且可能會在服務器處於負載狀態時發生變化。 我會將async
操作保留給預計會花費大量時間或預計會非常頻繁地調用的任務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.