Ответ 1
Как получилось, что он может сразу запустить первые 3 Задачи, но затем требуется 5-10 секунд для запуска Задачи 4, и после запуска Задачи 4 это займет 5-10 сек до начала Задачи 5 и так далее. Это что-то делает? Может кто-нибудь прояснить, что происходит?
По умолчанию при первом запуске этот параметр ThreadPool
выделяется с использованием минимального количества рабочих потоков. После того, как запланированы первые 4 задания, поток будет "наращивать", чтобы обрабатывать больше со временем, поэтому вы видите задержку.
В моей системе (которая имеет 8 ядер) первые 8 являются мгновенными, затем следующие два запускаются через секунду.
В вашем случае, если вы дважды запускаете тест, время второе, потоки будут немедленно запускаться. Это связано с тем, что после первого запуска ThreadPool должен иметь достаточное количество рабочих, чтобы сразу запланировать это.
Попробуйте следующее, чтобы увидеть это поведение в действии. Если вы оставите вызов SetMinThreads на месте, все они будут немедленно назначены. Если вы прокомментируете это, вы увидите, что в первый раз это займет некоторое время, но во второй раз (если вы дождитесь завершения потоков) потоки будут выполняться немедленно.
static void DoIt(string name)
{
Console.WriteLine("Hello {0} | {1} - {2}", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now);
Thread.Sleep(5000);
Console.WriteLine("Bye {0} | {1} - {2}", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now);
}
static void Main()
{
int workerThreads, complete;
ThreadPool.GetMinThreads(out workerThreads, out complete);
Console.WriteLine(workerThreads);
// Comment out this line to see the difference...
// WIth this commented out, the second iteration will be immediate
ThreadPool.SetMinThreads(100, complete);
Action run = () =>
{
for (int i = 0; i < 20; ++i)
{
int tmp = i;
Task.Factory.StartNew(() => DoIt(tmp.ToString()));
}
};
run();
Console.WriteLine("Press a key to run again...");
Console.ReadKey();
run();
Console.WriteLine("Press a key to exit...");
Console.ReadKey();
}
Обратите внимание, что это поведение на самом деле мало связано с TPL в целом - это больше используется по умолчанию TaskScheduler
, который просто передает задачи на ThreadPool
. Если вы должны были установить эти потоки с помощью подсказки LongRunning
в вашем вызове StartNew()
, например, все они будут запускаться немедленно (поскольку планировщик по умолчанию настроит новый выделенный поток и выполнит его немедленно).