【问题标题】:Use Entity Framework Core with ThreadPool without reaching maximum SQL Server connection使用 Entity Framework Core 和 ThreadPool 而不达到最大 SQL Server 连接
【发布时间】:2021-07-14 05:54:32
【问题描述】:

我尝试向我的 SQL Server 插入大量数据而未达到最大连接数。

我已经尝试在我的连接字符串中最大化池大小,如下所示:

optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Echo;Max Pool Size=5000;Pooling=True;");

是否可以为每个线程使用一个连接?

这是我的代码

    public static void GenerateMeridien()
    {
        List<Parallele> paralleleList = null;

        using (var context = new EchoContext())
        {
            paralleleList = context.Paralleles.ToList();
        }

        foreach (Parallele parallele in paralleleList)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(MeridienTaskCallback), parallele);
        }
    }

    private static void MeridienTaskCallback(object paralleleObj)
    {
        Parallele parallele = (Parallele)paralleleObj;

        // The context always reaches maximum connection because the garbage collector is not fast enough
        using (var context = new EchoContext())
        {
            List<Square> squareList = SquareLogic.GenerateSquare(parallele);
            context.Squares.AddRange(squareList);

            context.SaveChanges();
            Console.Write("*");
        }
    }

【问题讨论】:

  • 正确使用IDisposable(通常通过using)否定“垃圾收集器未运行”。究竟是什么连接(暂时)泄漏?
  • 请提供一些数字:数据量、频率等。
  • @tymtam 在他的回答中提到的问题是您的代码试图同时并行运行所有插入。解决方案是在任何时候简单地限制工人的数量。
  • 顺便说一句,您根本没有理由使用多线程。如果你切换到异步/等待,你将能够运行这个“单线程/异步/并发”。
  • 获取适当的 BulkCopy 库并在一批中插入所有内容。

标签: c# sql-server multithreading entity-framework-core threadpool


【解决方案1】:

选项 A。并行工作,保存一次

每次计算后都需要保存吗?你可以并行计算并保存吗?

List<Parallele> paralleleList = null;

using (var context = new EchoContext())
{
    paralleleList = context.Paralleles.ToList();
}

List<Square> squares = DoAllWorkInParallel(paralleleList);

// Save once:
using (var context = new EchoContext())
{
    context.Squares.AddRange(squares);
    context.SaveChanges();
}

选项 B. 一直保存

我认为你应该使用Parallel.ForEachMaxDegreeOfParallelism 或使用Task.WhenAll

Parallel.ForEach

例如:

public static async Task GenerateMeridien()
{
    List<Parallele> paralleleList = null;

    using (var context = new EchoContext())
    {
        paralleleList = context.Paralleles.ToList();
    }

    Parallel.ForEach(
        source: paralleleList,
        parallelOptions: new ParallelOptions{MaxDegreeOfParallelism = x},
        body: parallele => Work(parallele));

    
}

private static void Work(Parallele parallele)
{
    using (var context = new EchoContext())
    {
        List<Square> squareList = SquareLogic.GenerateSquare(parallele);
        context.Squares.AddRange(squareList);

        await context.SaveChanges();
    }
}

Task.WhenAll

public static async Task GenerateMeridien()
{
    List<Parallele> paralleleList = null;

    using (var context = new EchoContext())
    {
        paralleleList = context.Paralleles.ToList();
    }

    var tasks = new List<Task>();
    foreach (Parallele parallele in paralleleList)
    {
        tasks.Add(WorkAsync(parallele));
    }

    await Task.WhenAll(tasks.ToArray());
}

private static async Task WorkAsync(Parallele parallele)
{
    using (var context = new EchoContext())
    {
        List<Square> squareList = SquareLogic.GenerateSquare(parallele);
        context.Squares.AddRange(squareList);

        await context.SaveChangesAsync();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-05
    • 2020-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多