Задать вопрос

Как правильно распараллеливать выполнение цикла «For»?

Здравствуйте.

Я с помощью цикла for записывал двухмерный строковый массив в Excel:
for (var column = 1; column <= columns; column++)
{
    // Тело цикла, выполняющее функцию записи одного столбца в Excel документ.
}

После этого я решил ускорить процесс записи данных в Excel, путём параллельного выполнения цикла for:
Parallel.For(1, columns + 1, column =>
{
    // Тело цикла, выполняющее функцию записи одного столбца в Excel документ.               
});

Благодаря этому время записи снизилось в среднем на 16%.

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

P.S. Я так 6 раз перезагружал компьютер, и каждый раз после перезагрузки данные правильно записывались в Excel. Но как только я повторно запускал программу, данные записывались в Excel в случайном порядке.
P.P.S. При использовании обычного цикла for такой проблемы не возникает.
  • Вопрос задан
  • 361 просмотр
Подписаться 2 Простой Комментировать
Решения вопроса 2
@cicatrix
было бы большой ошибкой думать
Race Condition по всей видимости. Добро пожаловать в мир многопоточности. При параллельном исполнении, нет гарантии, что порядок сохранится. Кто первый встал, того и тапки.
Я бы вам посоветовал бить массив (или что там у вас в цикле) на 2, 3 ... N частей, строго отводя каждой части свои области (скажем, первый поток заполняет колонки 1...10, второй - 11..20 и т.д.) и запускал бы N синхронных циклов в разных потоках.
И в принципе, чтобы понять, как работает многопоточность, я бы для начала попробовал всё сделать вручную, при помощи старого доброго System.Threading.Thread. В Tasks многое спрятано "под капот", и можно на много граблей наступить.
Ответ написан
hePPer
@hePPer
попробуйте разбивать список колонок, и проходить их секциями отдельно, сохраняя общий порядок

public static void TestMethod()
        {
            var columns =new List<object>();//список колонок


            foreach(var groups in columns.ToChunks(100))
            {
                Parallel.ForEach(groups, new ParallelOptions { MaxDegreeOfParallelism = 10 },
                                 (group) =>
                                 {
                                     // Тело цикла, выполняющее функцию записи одного столбца в Excel документ. 
                                 });
            }
        }

        public static List<List<T>> ToChunks<T>(this List<T> list, int chunkSize)
        {
            if(chunkSize <= 0) { throw new ArgumentException("chunkSize must be greater than 0."); }

            List<List<T>> retVal = new List<List<T>>();
            int index = 0;
            while(index < list.Count)
            {
                int count = list.Count - index > chunkSize ? chunkSize : list.Count - index;
                retVal.Add(list.GetRange(index, count));

                index += chunkSize;
            }
            return retVal;
        }
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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