c# - 批量运行异步任务

标签 c# asynchronous async-await task-parallel-library

我正在异步运行一个存储过程(我需要运行相同的 SP 大约 150 次),如下所示:-

var queryTask = new List<Task>();
for (int i = 0; i < 150; i++)
{
      queryTask.Add(da.ExecuteSPAsync("Async" + i.ToString()));
}
Task.WhenAll(queryTask).Wait();

现在,它将创建 150 Tasks并执行它们。我可以分批拆分这些任务并运行它们吗?这会减少 SQL 服务器端的负载吗?

还是我应该考虑由 TPL 运行它?像这样:-
Parallel.For(0, 150, new ParallelOptions { MaxDegreeOfParallelism = 5 },
              x => da.ExecuteSP("PPWith5Threads" + x.ToString()));

哪一个在性能方面更好?这只是演示目的的一个示例,实际上我有一个自定义类型的集合,我需要在其上执行一些 SP。

最佳答案

因此,您可以为此使用信号量。信号量背后的概念是夜总会保镖场景,其中保镖对俱乐部(线程池)中允许的人数(线程)有限制,并且当人们离开时(线程完成)其他人可以进入(线程可以继续),直到极限。

所有线程都将启动,但它是 WaitAsync()这阻止了线程继续。 Release()正在发出一个线程重新进入线程池的信号。

这里的延迟产生了批处理的效果,因为每个线程都在大致等待相同的时间,然而,实际上你更有可能一次看到几个。

替补Delay(5000)使用随机 int 以获得更好的外观。

class Program
{
    static void Main(string[] args)
    {
        var runner = new SprocRunner(new DataAccess());

        var threads = new List<Task>();
        for (var i = 0; i < 150; i++)
        {
            threads.Add(runner.ExecuteSp($"Async {i}"));
        }

        Task.WaitAll(threads.ToArray());
    }
}

public class SprocRunner
{
    private readonly System.Threading.SemaphoreSlim batcher = new System.Threading.SemaphoreSlim(10, 10);
    private readonly DataAccess da;

    public SprocRunner(DataAccess da)
    {
        this.da = da;
    }

    public async Task ExecuteSp(string asyncTaskName)
    {
        await batcher.WaitAsync();

        try
        {
            await this.da.ExecuteSP(asyncTaskName);
        }
        catch (Exception e)
        {
        }
        finally
        {
            batcher.Release();
        }
    }
}

public class DataAccess
{
    public Task ExecuteSP(string name)
    {
        Console.WriteLine(name);

        return Task.Delay(5000);
    }
}

为什么不使用并行

在阅读了 Stephen Toub 之类的论文之后,情况是,如果您正在执行大量 I/O 绑定(bind)任务,那么在某些情况下使用 Parallel不是问题,它确实可以让你完成工作。要考虑的事情是线程创建不是不可忽略的成本,如果您请求的线程多于 ThreadPool 中存在的线程,则必须注入(inject)新线程。如果您处于一个大量使用 ASP.NET 等线程的环境中,这将成为一个问题。让大量线程阻塞在 I/O 工作上真的很糟糕,并且可能会使您的服务器停滞不前。

这是使用 Task 的地方抽象真正发挥作用,因为您可以运行所有这些任务,然后等待 I/O 响应 - 但非常重要 - 它们不会阻塞任何线程(除了等待结果的主线程),只有一次I/O 完成将简单地用于处理结果。

关于c# - 批量运行异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42511104/

相关文章:

c# - 不使用 XmlInclude 进行序列化

c# - 即使使用 ConfigureAwait(false),在 WebAPI 中同步调用异步方法也会死锁

c# - 过滤数据集中的多个数据表

node.js - 外部程序返回后Nodejs如何更新客户端?

c# - 如果我在不同的线程上同步运行,它会使每个线程异步吗?

javascript - 我应该如何在JavaScript中“屈服”?

javascript - 如何简化异步 axios post 方法的多个 'then' ?

c# - 序列化 MDI Winforms 以实现持久性

javascript - async/await 总是返回 promise

javascript - 异步.eachSeries : Callback already called