Почему Parallel.Invoke не может выполнить все действия? - PullRequest
1 голос
/ 31 июля 2010

Я работал над примером в учебнике о параллельном программировании на C #. Книга предлагает Parallel.Invoke может заменить создание, вызов и ожидание задач. Тем не менее, я попытался и обнаружил, что если я использую Parallel.Invoke, задачи не будут завершены до возврата значения. Но в теории Parallel.Invoke всегда должен ждать.

код:

    private byte[] getDataForGraph(int dataSize)
    {
        byte[] data = new byte[dataSize];


        Parallel.Invoke(
            () => Task.Factory.StartNew(() => generateGraphData(data, 0, pixelWidth / 8)),
            () => Task.Factory.StartNew(() => generateGraphData(data, pixelWidth / 8,
                pixelWidth / 4)),
            () => Task.Factory.StartNew(() => generateGraphData(data, pixelWidth / 4,
                pixelWidth * 3 / 8)),
            () => Task.Factory.StartNew(() => generateGraphData(data, pixelWidth * 3 / 8,
                pixelWidth / 2)));

        return data;
    }

И способ выполнения функции:

Task<byte[]> getDataTask = Task<byte[]>.Factory.StartNew(() => getDataForGraph(dataSize));
byte[] data = getDataTask.Result;

private void generateGraphData(byte[] data, int partitionStart, int partitionEnd) - это функция, заполняющая массив данных, от partitionStart до partitionEnd.

Если я запускаю программу, заполняется только часть массива. Но если я заменю Invoke на

Task first = Task.Factory.StartNew(() => generateGraphData(data, 0, pixelWidth / 8));
Task second = Task.Factory.StartNew(() => generateGraphData(data, pixelWidth / 8, pixelWidth / 4));
Task third = Task.Factory.StartNew(() => generateGraphData(data, pixelWidth / 4, pixelWidth * 3 / 8));
Task fourth = Task.Factory.StartNew(() => generateGraphData(data, pixelWidth * 3 / 8, pixelWidth / 2));
Task.WaitAll(first, second, third, fourth);

Программа работает как положено (массив полностью заполнен).

В чем здесь проблема?

Заранее спасибо.

1 Ответ

5 голосов
/ 31 июля 2010

Выполняет действия до их завершения. В вашем случае каждое действие должно вызывать Task.Factory.StartNew(...) - и , которые завершил; однако нет никакой гарантии, что каждая из этих задач была поставлена ​​в очередь / обработана. Разница в WaitAll (которую вы не называли в своем примере Parallel).

Одним из вариантов здесь было бы уменьшить это до:

Parallel.Invoke(
    () => generateGraphData(data, 0, pixelWidth / 8),
    () => generateGraphData(data, pixelWidth / 8, pixelWidth / 4),
    () => generateGraphData(data, pixelWidth / 4, pixelWidth * 3 / 8),
    () => generateGraphData(data, pixelWidth * 3 / 8, pixelWidth / 2)
);
...