ThreadPool.QueueUserWorkItem с лямбда-выражением и анонимным методом
-
09-09-2019 - |
Вопрос
Передача двух параметров новому потоку в 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 после этого никогда не изменяются.
В этом есть что-то неправильное?
Альтернативой является создание нового класса, который реализует неизменяемый тип с 3 членами:тест, s1 и s2.На данный момент это просто кажется дополнительной работой, не приносящей никакой пользы.
Решение
В этом нет ничего плохого.Компилятор, по сути, автоматически выполняет то, что вы описали как свою альтернативу.Он создает класс для хранения захваченных переменных (test, s1 и s2) и передает экземпляр делегата лямбде, который превращается в метод анонимного класса.Другими словами, если бы вы продолжили свою альтернативу, то в итоге получили бы что-то очень похожее на то, что компилятор только что сгенерировал для вас.
Другие советы
Для этого конкретного примера, нет, здесь нет ничего плохого.Состояние, которое вы передали в другой поток, полностью содержится, и ни один из задействованных типов не имеет проблем с привязкой к потоку.
Это хороший способ сделать это.Я не вижу никаких недостатков в использовании лямбд.Это просто и понятно.
То, на что вы смотрите, называется завершением.Как государства чакдж, компилятор генерирует класс во время компиляции, который соответствует членам, к которым осуществляется доступ за пределами замыкания.
Единственное, о чем вам нужно беспокоиться, это о том, есть ли у вас параметры ref или out .Хотя строки неизменяемы, ссылки на них (или любую переменную) ТАКОВЫМИ НЕ являются.
Одна из потенциальных проблем с шаблоном заключается в том, что он очень заманчиво расширить его до чего-то более общего, но менее безопасного, подобного этому (scratch code - не ожидайте, что это сработает):
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
}
}