Странное поведение, когда я не использую TaskCreationOptions.LongRunning - PullRequest
5 голосов
/ 14 марта 2011

У меня есть движок с произвольным количеством опрошенных, каждый из которых проводит свой опрос каждые несколько секунд.Я хочу, чтобы поллеры запускались в разных потоках, но каждый «опрос» в одном поллере должен быть последовательным, чтобы один происходил после следующего.Все работает, используя этот код, чтобы запустить процесс опроса:

    public void StartPolling()
    {
        Stopwatch watch = new Stopwatch();
        while (Engine.IsRunning)
        {
            Task task = Task.Factory.StartNew(() =>{
                watch.Restart();
                Poll();
                watch.Stop();
            },TaskCreationOptions.LongRunning);
            task.Wait();
            if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed);
        }
    }

Однако мне потребовалось некоторое время, чтобы обнаружить параметр TaskCreationOptions.LongRunning, который решил странную проблему, с которой я столкнулся, которую я до сих пор не понимаю,Без этой опции, если я запустил тест, который создает 1-3 из этих поллеров, все работало нормально.Если я создал 4+, то столкнулся со странным поведением.Три опрашивающих будут работать, один будет выполнять только один опрос, а остальные не будут опрашивать вообще.Это имеет полное значение, что мои задачи выполняются долго.В конце концов, они работают по всей длине моей программы.Но я не понимаю, почему я получил бы плохое поведение без этой опции.Любая помощь будет оценена.

Ответы [ 2 ]

12 голосов
/ 14 марта 2011

Если вы не используете флаг LongRunning, задача запланирована в потоке потоков, а не в его собственном (выделенном) потоке.Вероятно, это является причиной вашего поведенческого изменения - когда вы работаете без установленного флага LongRunning, вы, вероятно, получаете истощение пула потоков из-за других потоков в вашем процессе.

При этом вашприведенный выше код не имеет большого смысла.Вы запускаете выделенный поток (через Task .... StartNew with LongRunning), чтобы запустить задачу, а затем немедленно вызываете task.Wait(), который блокирует текущий поток.Было бы лучше сделать это последовательно в текущем потоке:

public void StartPolling()
{
    Stopwatch watch = new Stopwatch();
    while (Engine.IsRunning)
    {
        watch.Restart();
        Poll();
        watch.Stop();
        if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed);
    }
}
7 голосов
/ 14 марта 2011

TPL (и традиционный ThreadPool) ограничивает количество потоков в пуле (обычно небольшое кратное число ядер ЦП, обычно 2х ядер).Если вы пометите задачу как LongRunning, она знает, что задача не скоро завершится, и не может подвергнуть эту задачу ограничению потоков.

Без LongRunning, она предполагает, что ваша задача завершится быстро(чего не происходит), поэтому он остается в пределах потока.Затем, если вы создаете больше задач, чем ограничено потоками, и выполняемые задачи никогда не заканчиваются, TPL останавливает выполнение всех других задач, ожидая напрасно завершения этих запущенных задач (что они никогда не выполнят).

...