#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));