Ang*_*ker 9 .net c# multithreading task-parallel-library
我有以下代码:
var factory = new TaskFactory();
for (int i = 0; i < 100; i++)
{
var i1 = i;
factory.StartNew(() => foo(i1));
}
static void foo(int i)
{
Thread.Sleep(1000);
Console.WriteLine($"foo{i} - on thread {Thread.CurrentThread.ManagedThreadId}");
}
Run Code Online (Sandbox Code Playgroud)
我可以看到它一次只做4个线程(基于观察).我的问题:
PS我的盒子有4个核心.
PPS我需要具有特定数量的任务(并且不再需要)由TPL同时处理并最终得到以下代码:
private static int count = 0; // keep track of how many concurrent tasks are running
private static void SemaphoreImplementation()
{
var s = new Semaphore(20, 20); // allow 20 tasks at a time
for (int i = 0; i < 1000; i++)
{
var i1 = i;
Task.Factory.StartNew(() =>
{
try
{
s.WaitOne();
Interlocked.Increment(ref count);
foo(i1);
}
finally
{
s.Release();
Interlocked.Decrement(ref count);
}
}, TaskCreationOptions.LongRunning);
}
}
static void foo(int i)
{
Thread.Sleep(100);
Console.WriteLine($"foo{i:00} - on thread " +
$"{Thread.CurrentThread.ManagedThreadId:00}. Executing concurently: {count}");
}
Run Code Online (Sandbox Code Playgroud)
小智 15
当你Task在.NET 中使用时,你告诉TPL安排一项工作(通过TaskScheduler)来执行ThreadPool.请注意,工作将尽早安排,但调度程序认为合适.这意味着TaskScheduler将决定将使用多少个线程来运行n多个任务以及在哪个线程上执行哪个任务.
TPL经过精心调整,并在执行任务时继续调整算法.因此,在大多数情况下,它会尽量减少争用.这意味着如果您运行100个任务并且只有4个核心(您可以使用Environment.ProcessorCount它),那么在任何给定时间执行4个以上的线程都没有意义,否则它将需要进行更多的上下文切换.现在,有时您希望显式覆盖此行为.让我们说在你需要等待某种IO完成的情况下,这是一个完全不同的故事.
总之,请相信TPL.但是如果你坚持每个任务产生一个线程(并不总是一个好主意!),你可以使用:
Task.Factory.StartNew(
() => /* your piece of work */,
TaskCreationOptions.LongRunning);
Run Code Online (Sandbox Code Playgroud)
这告诉DefaultTaskscheduler为该工作明确生成一个新线程.
您也可以使用自己的Scheduler并将其传递给TaskFactory.你可以找到一大堆Schedulers HERE.
注意另一种替代方法是使用PLINQ默认情况下分析您的查询并决定是否并行化它会产生任何好处,再次在阻塞IO的情况下,您确定启动多个线程将导致更好的执行,您可以强制执行WithExecutionMode(ParallelExecutionMode.ForceParallelism)然后使用你的并行性可以使用WithDegreeOfParallelism来提供有关使用多少线程的提示,但是请记住,不能保证你会得到那么多线程,如MSDN所说:
设置要在查询中使用的并行度.并行度是将用于处理查询的并发执行任务的最大数量.
最后,我强烈建议您阅读THIS一系列关于Threading和的文章TPL.
如果将任务数量增加到例如 1000000 个,您将看到随着时间的推移产生更多的线程。TPL 倾向于每 500 毫秒注入一次。
TPL 线程池不理解 IO 密集型工作负载(睡眠是 IO)。在这些情况下,依靠 TPL 来选择正确的并行度并不是一个好主意。TPL 完全无能为力,并且根据对吞吐量的模糊猜测来注入更多线程。也是为了避免死锁。
在这里,TPL 策略显然没有用,因为添加的线程越多,获得的吞吐量就越大。在这种人为的情况下,每个线程每秒可以处理一个项目。TPL 对此一无所知。将线程数限制为核心数是没有意义的。
什么决定了一次使用的线程数?
几乎没有记录 TPL 启发法。他们经常出错。特别是在这种情况下,随着时间的推移,它们将产生无限数量的线程。使用任务管理器亲自查看。让它运行一个小时,您将拥有 1000 个线程。
我怎样才能找回这个号码?我怎样才能更改这个号码?
您可以检索其中一些数字,但这不是正确的方法。如果您需要有保证的 DOP,您可以使用AsParallel().WithDegreeOfParallelism(...)或自定义任务调度程序。您也可以手动启动LongRunning任务。不要弄乱进程全局设置。