Rah*_*ngh 7 c# asynchronous task-parallel-library async-await
我正在异步运行一个存储过程(我需要运行相同的 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();
Run Code Online (Sandbox Code Playgroud)
现在,它将创建 150Tasks
并执行它们。我可以批量拆分这些任务并运行它们吗?这会减少 SQL 服务器端的负载吗?
还是我应该考虑 TPL 来运行它?像这样:-
Parallel.For(0, 150, new ParallelOptions { MaxDegreeOfParallelism = 5 },
x => da.ExecuteSP("PPWith5Threads" + x.ToString()));
Run Code Online (Sandbox Code Playgroud)
哪一个在性能方面更好?这只是演示目的的一个示例,实际上我有一个自定义类型的集合,我需要在其上执行一些 SP。
因此,您可以为此使用信号量。信号量背后的概念是夜总会保镖场景,其中保镖对俱乐部(线程池)中允许的人数(线程)有限制,当人们离开(线程完成)时,其他人可以进入(线程可以继续) ),达到极限。
所有线程都将启动,但是它WaitAsync()
阻止了线程继续。在Release()
被通知线程重新进入线程池。
这里的延迟给出了批处理的效果,因为每个线程大致等待相同的时间,但是,实际上一次看到几个线程的可能性更大。
替换Delay(5000)
为 random 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);
}
}
Run Code Online (Sandbox Code Playgroud)
在阅读了 Stephen Toub 之类的论文后,情况是,如果您正在执行大量 I/O 绑定任务,那么在某些情况下使用Parallel
不是问题,它确实可以让您完成工作。要考虑的事情是线程创建不是一个不可忽略的成本,如果您请求的线程多于 ThreadPool 中存在的线程,它将不得不注入新的线程。如果您处于一个大量使用线程(如 ASP.NET)的环境中,这就会成为一个问题。大量线程阻塞 I/O 工作真的很糟糕,可能会使您的服务器停滞不前。
这就是使用Task
抽象真正发挥作用的地方,因为您可以运行所有这些任务,然后等待 I/O 响应——但真正重要的是——它们不会阻塞任何线程(除了主线程等待结果),只有在 I/O 完成后,才会简单地使用线程来处理结果。
归档时间: |
|
查看次数: |
8541 次 |
最近记录: |