запуск нескольких экземпляров метода Одновременно c # [duplicate]

Это означает, что указанная переменная не указана ни на что. Я мог бы сгенерировать это так:

SqlConnection connection = null;
connection.Open();

Это вызовет ошибку, потому что, пока я объявил переменную «connection», она не указала ни на что. Когда я пытаюсь вызвать член «Open», для его устранения нет ссылки, и он будет вызывать ошибку.

Чтобы избежать этой ошибки:

  1. Всегда инициализируйте свои объекты, прежде чем пытаться что-либо с ними делать.
  2. Если вы не уверены, что объект имеет значение null, проверьте его с помощью object == null.

Инструмент Resharper JetBrains определит каждое место в вашем коде, которое имеет возможность ошибки нулевой ссылки, позволяя вам ввести нулевую проверку. Эта ошибка является источником ошибок номер один, IMHO.

232
задан stackoverflowuser 15 February 2011 в 21:33
поделиться

4 ответа

Первый вариант гораздо лучше.

Parallel.ForEach, внутренне, использует Partitioner<T> для распространения вашей коллекции на рабочие элементы. Он не будет выполнять одну задачу для каждого элемента, а скорее сделает это, чтобы снизить задействованные служебные данные.

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

FYI. Используемый разделитель можно контролировать с помощью используя соответствующие перегрузки для Parallel.ForEach , если это необходимо. Подробнее см. Пользовательские разделители в MSDN.

Основное различие во время выполнения - это второе действие будет асинхронным. Это можно продублировать с помощью Parallel.ForEach, выполнив:

Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));

Поступая таким образом, вы по-прежнему пользуетесь разделителями, но не блокируете до завершения операции.

269
ответ дан Reed Copsey 27 August 2018 в 05:53
поделиться

Я сделал небольшой эксперимент по запуску метода «1000000000» раз с «Parallel.For» и одним с объектами «Задача».

Я измерил время процессора и нашел Parallel более эффективным. Parallel.For делит вашу задачу на небольшие рабочие элементы и выполняет их на всех ядрах в оптимальном порядке. При создании множества объектов задач (FYI TPL будет использовать пул потоков внутри) будет перемещать каждое выполнение по каждой задаче, создавая больше стресса в ящике, что видно из приведенного ниже эксперимента.

Я также создал небольшое видео, которое объясняет базовый TPL, а также продемонстрировало, как Parallel.For использует ваше ядро ​​более эффективно http://www.youtube.com/watch?v=No7QqSc5cl8 по сравнению с обычными задачами и потоками.

Эксперимент 1

Parallel.For(0, 1000000000, x => Method1());

Эксперимент 2

for (int i = 0; i < 1000000000; i++)
{
    Task o = new Task(Method1);
    o.Start();
}

Processor time comparison [/g1]

72
ответ дан chue x 27 August 2018 в 05:53
поделиться

Parallel.ForEach будет оптимизировать (возможно, даже не запускать новые потоки) и блокировать до тех пор, пока цикл не будет завершен, а Task.Factory явно создаст новый экземпляр задачи для каждого элемента и вернется до их завершения (асинхронные задачи). Parallel.Foreach намного эффективнее.

16
ответ дан Sogger 27 August 2018 в 05:53
поделиться

На мой взгляд, самый реалистичный сценарий - когда задачи выполняют тяжелую операцию. Подход Шивпрасада больше фокусируется на создании объекта / распределении памяти, чем на самом вычислении. Я провел исследование, назвав следующий метод:

public static double SumRootN(int root)
{
    double result = 0;
    for (int i = 1; i < 10000000; i++)
        {
            result += Math.Exp(Math.Log(i) / root);
        }
        return result; 
}

Выполнение этого метода занимает около 0,5 сек.

Я назвал его 200 раз, используя Parallel:

Parallel.For(0, 200, (int i) =>
{
    SumRootN(10);
});

Затем я назвал его 200 раз, используя старомодный способ:

List<Task> tasks = new List<Task>() ;
for (int i = 0; i < loopCounter; i++)
{
    Task t = new Task(() => SumRootN(10));
    t.Start();
    tasks.Add(t);
}

Task.WaitAll(tasks.ToArray()); 

Первый случай завершен в 26656 мсек, второй - в 24478мс. Я повторил это много раз. Каждый раз, когда второй подход маргиналист быстрее.

6
ответ дан user1089583 27 August 2018 в 05:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: