Есть ли накладные расходы при использовании анонимных методов? - PullRequest
7 голосов
/ 22 февраля 2012

Я хотел бы знать, есть ли какие-либо накладные расходы, связанные с использованием анонимных методов при создании фонового рабочего.

например:

public void SomeMethod()
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += (sender, e) =>
    {
        //large amount of code
    }

    worker.RunWorkerAsync();
}

Будет ли приведенный выше пример лучше или хуже определения //large amount of code в отдельном методе?

Существуют ли какие-либо накладные расходы при определении встроенного метода фонового рабочего, особенно если часто вызывается SomeMethod()?

Ответы [ 7 ]

5 голосов
/ 22 февраля 2012

Существует небольшая разница в том, как именованные методы и анонимные методы обрабатываются при создании делегата из них.

Делегаты для анонимных методов кэшируются, поэтому есть небольшая нагрузка для проверки, существует ли уже делегат в кэше. С другой стороны, если вы запустите метод более одного раза, он будет использовать кэшированный делегат вместо создания нового.

Делегаты для именованных методов не кэшируются, поэтому они будут создаваться каждый раз.

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

2 голосов
/ 22 февраля 2012

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

Что касается сгенерированного IL, если лямбда не закрывается по каким-либо переменным, то сгенерированный IL-код такой же, как если бы вы поместили код в метод с обычным именем (за исключением того, что сгенерированный метод имеет невыразимое имя).

С другой стороны, если вы закрываете некоторую переменную, компилятор создает класс замыкания для хранения этой переменной в поле. И доступ к полю немного дороже, чем доступ к локальной переменной.

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

1 голос
/ 22 февраля 2012

Всякий раз, когда анонимный метод (включая лямбды) закрывает переменные, компилятор создает класс для хранения этих переменных для вас. Всякий раз, когда создается делегат, новый экземпляр этого класса тоже. Это, очевидно, добавляет дополнительную работу для среды выполнения, но, как правило, незначительно в большинстве ситуаций.

0 голосов
/ 26 марта 2019
0 голосов
/ 22 февраля 2012

Декомпилятор сказал следующее:

[CompilerGenerated]
private static DoWorkEventHandler CS$<>9__CachedAnonymousMethodDelegate1;

[CompilerGenerated]
private static void <SomeMethod1>b__0(object sender, DoWorkEventArgs e)
{
    throw new NotImplementedException();
}

public void SomeMethod1()
{
    BackgroundWorker worker = new BackgroundWorker();
    BackgroundWorker backgroundWorker = worker;
    backgroundWorker.DoWork += (object sender, DoWorkEventArgs e) => throw new NotImplementedException();
    worker.RunWorkerAsync();
}

public void SomeMethod2()
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += worker_DoWork;
    worker.RunWorkerAsync();
}

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    throw new NotImplementedException();
} 

Редактировать:

Глядя на код IL, при создании / назначении метода для делегирования в первый раз очень мало затрат.

0 голосов
/ 22 февраля 2012

Это в основном влияет на читабельность - большие объемы кода в одном месте почти никогда не бывают хорошими; -)

С точки зрения производительности см. Когда преждевременная оптимизация?

0 голосов
/ 22 февраля 2012

Я тестировал это на днях (с помощью класса StopWatch). Насколько я могу судить, между вызовами метода напрямую не было заметной разницы в производительности ...

SomeMethod();

... или анонимным способом ...

() => SomeMethod();
...