Здравствуйте, _NN_, Вы писали:
_NN>Тогда мы получаем лишний расход в виде Interlocked.Increment и выведем лог только после того как вся работа окончится в отличии от начального кода.
Interlocked.Increment это вообще мелочи, можно пренебречь. Внутри Parallel.ForEach тоже свои Interlocked.Increment есть, если уж на то пошло.
По поводу лога — если уж очень хочется, чтобы логировал как можно раньше, то сделай враппер для своей enumerable, который на последнем MoveNext будет сразу счётчик в лог писать.
Здравствуйте, _NN_, Вы писали:
_NN>Как вы решаете эту задачу ?
Какую задачу?
В исходном коде до завершения обработки выводится отладочная инфа о числе созданных тасков (не знаю что это даёт правда).
В предложенном изменении сначала выполняется обработка всех элементов, а потом выводится в лог информация о тасках,
хотя вроде и смысл изменений в том, чтобы таски не создавать и по факту это просто число обрабатываемых элементов.
Задача в итоге чисто вывести что-то в лог или в чём-то другом?
_NN>Тогда мы получаем лишний расход в виде Interlocked.Increment и выведем лог только после того как вся работа окончится в отличии от начального кода.
Interlocked.Increment дешевле, чем таски создавать. И вообще Interlocked.Increment — довольно дешёвая штука. Если таски настолько короткие, что начинает играть роль лишний Interlocked.Increment, и вообще, если ты его замечаешь, то пора переходить к частным решениям конкретно для этого места в конкретном коде.
У IEnumerable enumerable нет Count, иначе не было бы вопроса.
А вызов Enumerable.Count() приведёт к двойному обходу перечисления, что тоже не подходит.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, _NN_, Вы писали:
_NN>>У IEnumerable enumerable нет Count, иначе не было бы вопроса. _>Что мешает добавить в свой интерфейс с количеством элементов. _>Вы же это список заполняли как-то.
Ну к примеру у меня LINQ выражение какое-нибудь.
_NN>>А вызов Enumerable.Count() приведёт к двойному обходу перечисления, что тоже не подходит. _>Почему? Пока идёт выполнение ваших задач, что мешает пройтись по списку еще раз? (Кроме религиозных соображений)
Это если такая возможность есть.
Не каждый IEnumerable даст пройтись два раза без последствий.
Недостаток очевиден, мы создаём таск на каждый элемент, и лучше использовать Parallel.ForEach.
Однако с помощью Parallel.ForEach невозможно получить количество элементов.
В вышеприведённом примере мы их получаем неявно за счёт использования List.
Как вариант можно хранить переменную и автономно увеличивать:
int count = 0;
Parallel.ForEach(enumerable, element =>
{
Interlocked.Increment(ref count);
Logger.Info($"Running task {element}");
});
Logger.Info($"Run {count} tasks");
Тогда мы получаем лишний расход в виде Interlocked.Increment и выведем лог только после того как вся работа окончится в отличии от начального кода.
Здравствуйте, _NN_, Вы писали:
_NN>У IEnumerable enumerable нет Count, иначе не было бы вопроса.
Что мешает добавить в свой интерфейс с количеством элементов.
Вы же это список заполняли как-то.
_NN>А вызов Enumerable.Count() приведёт к двойному обходу перечисления, что тоже не подходит.
Почему? Пока идёт выполнение ваших задач, что мешает пройтись по списку еще раз? (Кроме религиозных соображений)
Здравствуйте, _NN_, Вы писали:
_NN>Ну к примеру у меня LINQ выражение какое-нибудь.
И что вам мешает реализовать несколько интерфейсов?
_NN>Это если такая возможность есть. _NN>Не каждый IEnumerable даст пройтись два раза без последствий.
Это уже кривые реализации. В IEnumerable есть который должен переходить в начало.
IEnumerable.Reset
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, _NN_, Вы писали:
_NN>>Ну к примеру у меня LINQ выражение какое-нибудь. _>И что вам мешает реализовать несколько интерфейсов?
Ну например у меня энумератор отправляет данные на сервер и ждёт ответа, а повторный проход даст другой результат.
А в руках у меня только IEnumerable.
Да что угодно может быть.
_>>И что вам мешает реализовать несколько интерфейсов?
_NN>Ну например у меня энумератор отправляет данные на сервер и ждёт ответа, а повторный проход даст другой результат.
Что мешает от сервера получить количество элементов? _NN>А в руках у меня только IEnumerable.
Сделайте копию. _NN>Да что угодно может быть.
Так и исключения можно кидать при переходе к следующему элементу.
Здравствуйте, _NN_, Вы писали:
_NN>Ну например у меня энумератор отправляет данные на сервер и ждёт ответа, а повторный проход даст другой результат. _NN>А в руках у меня только IEnumerable. _NN>Да что угодно может быть.
С такой постановкой исходный вопрос вообще не имеет значения. Делай хоть так, хоть эдак — на скорость не влияет. И Interlocked.Increment, и создание тасков вместе с последующим GC, в обычном случае настолько быстрее, чем запрос к серверу на каждый enumerable, что разницу нельзя будет заметить.
Здравствуйте, kov_serg, Вы писали:
_NN>>У IEnumerable enumerable нет Count, иначе не было бы вопроса. _>Что мешает добавить в свой интерфейс с количеством элементов. _>Вы же это список заполняли как-то.
Это абстракция IEnumerable. Количество элементов никому не известно на момент получения первых элементов. Иначе это был бы ICollection.
_NN>>А вызов Enumerable.Count() приведёт к двойному обходу перечисления, что тоже не подходит. _>Почему? Пока идёт выполнение ваших задач, что мешает пройтись по списку еще раз? (Кроме религиозных соображений)
Начать с того, что это не список. Повторный проход по IEnumerable может вызвать повторный вызов SELECT * FROM, например. С совершенно иным результатом.
Всем спасибо за мысли и советы.
На данный момент проще привести всё заранее к массиву так как количество не превысит нескольких тысяч.
А вот создавать тысячи таксов это гораздо хуже.