Сомнительная задержка выполнения пула потоков - PullRequest
3 голосов
/ 14 августа 2010

Я вызвал BeginInvoke для 10 делегатов в цикле.Вместо использования 10 потоков пул потоков использует только два / три потока для выполнения делегатов.Может кто-нибудь объяснить, пожалуйста, причину этого?Выполнение делегата занимает всего несколько мс (менее 10 мс).

Когда я регистрировал параметры пула потоков перед вызовом BeginInvoke, это указывало, что Min Threads = 2, Max Threads = 500, Available threads = 498.


Я получил проблему, когда вызвал следующий управляемый код C ++.

void EventHelper::FireAndForget(Delegate^ d, ... array<Object^>^ args)
            {
                try
                {
                    if (d != nullptr)
                    {                                           
                        array<Delegate^>^ delegates = d->GetInvocationList();   

                        String^ message1 = String::Format("No of items in the event {0}",delegates.Length);
                        Log(LogMessageType::Information,"EventHelper.FireAndForget", message1);

                        // Iterating through the list of delegate methods.
                        for each(Delegate^ delegateMethod in delegates)
                        {
                            try
                            {
                                int minworkerThreads,maxworkerThreads,availworkerThreads, completionPortThreads;
                                ThreadPool::GetMinThreads(minworkerThreads, completionPortThreads);
                                ThreadPool::GetMaxThreads(maxworkerThreads, completionPortThreads);
                                ThreadPool::GetAvailableThreads(availworkerThreads, completionPortThreads);

                                String^ message = String::Format("FireAndForget Method {0}#{1} MinThreads - {2}, MaxThreads - {3} AvailableThreads - {4}",
                                                delegateMethod->Method->DeclaringType, delegateMethod->Method->Name, minworkerThreads, maxworkerThreads, availworkerThreads);

                                Log(LogMessageType::Information,"EventHelper.FireAndForget", message);

                                DynamicInvokeAsyncProc^ evtDelegate = gcnew DynamicInvokeAsyncProc(this, &EventHelper::OnTriggerEvent);
                                evtDelegate->BeginInvoke(delegateMethod, args, _dynamicAsyncResult, nullptr); //FIX_DEC_09 Handle Leak    
                            }
                            catch (Exception^ ex)
                            {
                                String^ message = String::Format("{0} : DynamicInvokeAsync of '{1}.{2}' failed", _id,
                                                                    delegateMethod->Method->DeclaringType, d->Method->Name);

                                Log(LogMessageType::Information,"EventHelper.FireAndForget", message);                              
                            }
                        }
                    }
                    else
                    {                   
                    }
                }
                catch (Exception^ e)
                {
                    Log(LogMessageType::Error, "EventHelper.FireAndForget", e->ToString());
                }

            }

Этот метод указан в делегате

void EventHelper::OnTriggerEvent(Delegate^ delegateMethod, array<Object^>^ args)
            {
                try
                {
                    int minworkerThreads,maxworkerThreads,availworkerThreads, completionPortThreads;
                    ThreadPool::GetMinThreads(minworkerThreads, completionPortThreads);
                    ThreadPool::GetMaxThreads(maxworkerThreads, completionPortThreads);
                    ThreadPool::GetAvailableThreads(availworkerThreads, completionPortThreads);

                    String^ message = String::Format("OnTriggerEvent Method {0}#{1} MinThreads - {2}, MaxThreads - {3} AvailableThreads - {4}",
                                    delegateMethod->Method->DeclaringType, delegateMethod->Method->Name, minworkerThreads, maxworkerThreads, availworkerThreads);
                    Log(LogMessageType::Information,"EventHelper::OnTriggerEvent", message);

                    message = String::Format("Before Invoke Method {0}#{1}",
                                                delegateMethod->Method->DeclaringType, delegateMethod->Method->Name);
                    Log(LogMessageType::Information,"EventHelper::OnTriggerEvent", message);

                    // Dynamically invokes (late-bound) the method represented by the current delegate. 
                    delegateMethod->DynamicInvoke(args);
                    message = String::Format("After Invoke Method {0}#{1}",
                                                delegateMethod->Method->DeclaringType, delegateMethod->Method->Name);
                    Log(LogMessageType::Information,"EventHelper::OnTriggerEvent", message);
                }
                catch (Exception^ ex)
                {
                    Log(LogMessageType::Error, "EventHelper.OnTriggerEvent", ex->ToString());
                }
            }

Ответы [ 2 ]

6 голосов
/ 14 августа 2010

Вы не хотели бы, чтобы для этого было создано 10 потоков.Оптимальная ситуация - иметь столько активных потоков, сколько у вас ядер.Вы обнаружите, что ThreadPool.MinThreads равен количеству логических процессоров на вашем ПК.

Будут созданы дополнительные потоки, но ThreadPool намеренно задерживает это.Алгоритм в Fx4 был улучшен, см. на этой странице .Беглый взгляд на картинку внизу поможет вам понять принцип.

Дополнительные потоки полезны только для компенсации заблокированных потоков, но это трудно понять точно.

4 голосов
/ 14 августа 2010

Пул потоков преднамеренно ждет некоторое время, прежде чем запускать новые потоки - если в любом случае делегаты выполняются быстро (что звучит так, как они это делают), эффективнее выполнять их в нескольких потоках, чем ускорять новые.

Из документов для ThreadPool:

Когда все потоки пула потоков были назначенный на задачи, пул потоков не сразу начинает создавать новые холостые темы. Избежать излишне выделяя пространство стека для потоков, это создает новые простоя нити с интервалами. Интервал в настоящее время полсекунды, хотя это может измениться в будущих версиях .NET Framework. NET Framework.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...