【发布时间】:2018-01-25 23:41:07
【问题描述】:
我正在 EF 上运行性能测试,因为我们在服务器上运行并发调用时遇到了一些问题。
这是我针对北风数据库执行的测试,数据库中有 20,000 名额外员工以减慢检索速度
单次执行通常在大约 451 毫秒内返回,但是当并行调用时,我似乎看到了一些奇怪的额外执行时间
当我运行 10 个并发调用时,开销是我的 4 倍。这可能看起来微不足道,但当我在我的数据库上执行操作时,你会发现它变得更糟了。
运行 sp_whoisactive 时,您可以看到 sql 已经完成,正在等待发回 (246ms)ASYNC_NETWORK_IO
Sql 不是瓶颈。
class Program
{
public static int MAX_IO_THREADS = 2000;
public static int MIN_IO_THREADS = 1000;
public static int CONCURRENT_CALLS = 10;
static void Main(string[] args)
{
ConfigureThreadPool();
WarmUpContexts();
ProfileAction();
Console.ReadKey();
}
protected static void ProfileAction()
{
var callRange = Enumerable.Range(0, CONCURRENT_CALLS);
var stopwatch = new Stopwatch();
stopwatch.Start();
var results = new ConcurrentDictionary<int, string>();
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 512 };
Parallel.ForEach(callRange, parallelOptions, i =>
{
var callSw = new Stopwatch();
callSw.Start();
var result = RunTest();
callSw.Stop();
results.TryAdd(i, $"Call Index: {i} took {callSw.ElapsedMilliseconds} milliseconds to complete");
});
stopwatch.Stop();
var milliseconds = stopwatch.ElapsedMilliseconds;
foreach (var result in results.OrderBy(x => x.Key))
{
Console.WriteLine(result);
}
Console.WriteLine("Total Time " + milliseconds);
}
public static void ConfigureThreadPool()
{
ThreadPool.GetMinThreads(out var defaultMinWorkerCount, out var _);
ThreadPool.GetMaxThreads(out var defaultMaxWorkerCount, out var _);
ThreadPool.SetMaxThreads(defaultMaxWorkerCount, MAX_IO_THREADS);
var successMin = ThreadPool.SetMinThreads(defaultMinWorkerCount, MIN_IO_THREADS);
}
static void WarmUpContexts()
{
using (var stagingContext = new NORTHWNDEntities())
{
stagingContext.Employees.First();
}
}
static int RunTest()
{
using (var context = new Entities())
{
var employees = context.Employees.ToArray();
return employees.Length;
}
}
}
如何优化我的线程的性能,以便它们真正返回 NOTE 如果我调用 async 这将永远挂起,
这可能是 .net 中的错误吗?
【问题讨论】:
-
MaxDegreeOfParallelism = 512除非你的 CPU 上有 512 个逻辑内核,我认为这不太可能,否则这将完全破坏你的应用程序的性能 -
@KevinGosse 我也用 less 测试过,它也有同样的问题
-
为什么要使用每次迭代中创建的 dbcontext?您对数据库的并行查询太多。此外,
ToArray方法也可能会耗费时间和内存,因为数组会进入大型对象堆,默认情况下不会对其进行优化 -
@VMAtm,Entityframework 上下文不是线程安全的,而且,我试图模拟请求的行为。如何优化堆
-
堆不应该被优化,不应该被施压 - 只是不要创建数组,使用一些其他结构,除非你完全需要数组
标签: c# multithreading entity-framework task-parallel-library