ThreadPool.QueueUserWorkItem с выражением лямбда и анонимным методом
Передача двух параметров в новый поток в threadpool иногда может быть сложной, но, похоже, что с лямбда-выражениями и анонимными методами я могу это сделать:
public class TestClass
{
public void DoWork(string s1, string s2)
{
Console.WriteLine(s1);
Console.WriteLine(s2);
}
}
try
{
TestClass test = new TestClass();
string s1 = "Hello";
string s2 = "World";
ThreadPool.QueueUserWorkItem(
o => test.DoWork(s1, s2)
);
}
catch (Exception ex)
{
//exception logic
}
Теперь я, конечно, упростил этот пример, но эти точки являются ключевыми:
- Передаваемые объекты строки неизменяемы и, следовательно, потокобезопасны
- Переменные s1 и s2 объявляются в пределах области try, которые я выхожу сразу же после очередности работы в пул потоков, поэтому переменные s1 и s2 никогда не изменяются после этого.
С этим что-то не так?
Альтернативой является создание нового класса, который реализует неизменяемый тип с тремя членами: test, s1 и s2. Это просто похоже на дополнительную работу без каких-либо преимуществ на данный момент.
Ответы
Ответ 1
В этом нет ничего плохого. Компилятор по существу делает автоматически то, что вы описали как свою альтернативу. Он создает класс для хранения захваченных переменных (test, s1 и s2) и передает экземпляр делегата в лямбда, который превращается в метод в анонимный класс. Другими словами, если вы воспользовались своей альтернативой, вы в конечном итоге сотворили бы очень похожее на то, что только что сгенерировал компилятор для вас.
Ответ 2
В этом конкретном примере нет ничего плохого здесь. Состояние, в котором вы перешли в другой поток, полностью содержится, и ни один из типов не связан с проблемами присоединения потоков.
Ответ 3
Это хороший способ сделать это. Я не вижу недостатков в использовании лямбда. Это просто и чисто.
Ответ 4
То, что вы смотрите, называется закрытием. Как chuckj states, компилятор генерирует класс во время компиляции, который соответствует элементам, доступ к которым осуществляется за пределами закрытия.
Единственное, о чем вам нужно беспокоиться, - это иметь параметры ref или out. Хотя строки неизменяемы, ссылки на них (или любые переменные) не являются.
Ответ 5
Одна потенциальная проблема с шаблоном заключается в том, что очень заманчиво расширять его на нечто более общее, но менее безопасное, как это (код нуля - не ожидайте, что он будет работать):
public static void QueueTwoParameterWorkItem<T1, T2>(T1 value1, T2 value2, workDelegate<T1,T2> work)
{
try
{
T1 param1 = value1;
T2 param2 = value2;
ThreadPool.QueueUserWorkItem(
(o) =>
{
work(param1, param2);
});
}
catch (Exception ex)
{
//exception logic
}
}