SmartThreadPool — Возможно ли передать метод делегирования с параметрами метода?

#c# #multithreading #entity-framework

#c# #многопоточность #entity-framework

Вопрос:

У меня есть длительный процесс, ImportProductInformation вызываемый консольным приложением, который я пытаюсь ускорить, который, как представляется, является отличным кандидатом для объединения потоков, поэтому я немного поискал и наткнулся на SmartThreadPool в CodeProject и пытаюсь его реализовать.

ImportProductInformation в настоящее время требуется «элемент», который представляет собой всего лишь одну строку entity-framework, извлеченную из списка. SmartThreadPool использует вызываемый делегат "WorkItemCallback" , но если я создаю его, как показано ниже, он жалуется на «Ожидаемое имя метода» в цикле foreach на smartThreadPool.QueueWorkItem , поскольку, похоже, я не могу передать свои параметры делегированному методу. Чего мне здесь не хватает? Я уверен, что это что-то глупое … новичку не хватает опыта работы с делегатами…любая помощь была бы оценена:

     public static void ImportProductInformation_Exec()
    {
        // List
        List<productinformation> _list = GetProductInformation();

        // Import
        if (_list != null)
        {
            SmartThreadPool smartThreadPool = new SmartThreadPool();

            foreach (var item in _list)
            {
                smartThreadPool.QueueWorkItem
                  (new WorkItemCallback
                    (ImportProductInformation(item)));
            }

            smartThreadPool.WaitForIdle();
            smartThreadPool.Shutdown();
        }
    }

    public void ImportProductInformation(productinformation item)
    {
        // Do work associated with "item" here
    }
  

Если я изменю цикл на этот, я получу «Метод используется как тип» в ошибке сборки:

             foreach (var item in _list)
            {
                ImportProductInformation ipi = 
                  new ImportProductInformation(item);

                smartThreadPool.QueueWorkItem(new WorkItemCallback(ipi));
            }
  

В итоге получилось заставить его работать с этим:

 public class ProductInformationTaskInfo
{
    public productinformation ProductInformation;

    public ProductInformationTaskInfo(productinformation pi)
    {
        ProductInformation = pi;
    }
}

public class PI
{
    foreach (var item in _list)
    {
        ProductInformationTaskInfo pi = 
          new ProductInformationTaskInfo(item);
        smartThreadPool.QueueWorkItem
          (new WorkItemCallback
            (ImportProductInformation), pi);
    }

    public static object ImportProductInformation(Object _pi)
    {
        ProductInformationTaskInfo pi = (ProductInformationTaskInfo)_pi;
        var item = pi.ProductInformation;

        // Do work here
    }
}
  

Комментарии:

1. Вам нужен пул потоков? Разве вы не можете просто использовать System.Threading.Thread ?

2. SmartThreadPool предлагает гораздо больше, чем просто стандартный поток. Если я не смогу его использовать, я обязательно вернусь к System.Threading.Thread .

Ответ №1:

Я не знаю или не имею SmartThreadPool, следующее является приблизительным:

 foreach (var item in _list)
{
   var itemCopy = item;
   smartThreadPool.QueueWorkItem
              (dummy => ImportProductInformation(itemCopy));
}
  

Возможно, вам придется внести некоторые исправления.
Это работает, потому что лямбда-выражение фиксирует переменную из содержащего метода. И именно поэтому вам нужна itemCopy.

Но обратите внимание, что обычный ThreadPool не подходит для длительных задач, то же самое может относиться и к SmartThreadPool. Также следует ограничить количество потоков, и когда ImportProductInformation выполняет в основном потоки ввода-вывода, это может вообще не помочь.

Комментарии:

1. Выполнение каждой строки занимает около 15 секунд, поэтому я предполагаю, что пул потоков должен быть подходящим. SmartThreadPool добавляет совсем немного к значению по умолчанию. NET ThreadPool … codeproject.com/KB/threads/smartthreadpool.aspx

2. Странно, не уверен почему, но SmartThreadPool не обрабатывает лямбда-выражение корректно. Когда он создает очередь WorkItem, он повторяет один элемент из списка снова и снова. Я попробовал несколько вариантов, но в итоге получил свое оригинальное решение с объектом обратного вызова.

3. @Paul, Вы использовали переменную itemCopy? Это важно.

4. Ах, нет, я этого не делал… имеет смысл

Ответ №2:

Вы можете использовать анонимные методы:

 int a = 15;
String b = "hello world!";
ThreadPool.QueueUserWorkItem((state)=>SomeFunction(a,b));