Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1

Parallel.ForEach что не верно? Не компилируется

14.06.2014, 01:38. Показов 1585. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    class Program
    {
        static void Main(string[] args)
        {
            ParallelOptions parOpt = new ParallelOptions();
            SynchronizationContext context = SynchronizationContext.Current;
 
            var localInit = new Func<WebClient>(
                () =>
                {
                    var webClient = new WebClient();
                    webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
                    return webClient;
                });
 
            var body = new Func<UserViewModel, ParallelLoopState, WebClient, ParWebLinkSet>(
                (user, pLoopState, webClient) =>
                {
                    var set = new ParWebLinkSet();
                    set.Bytes = webClient.DownloadData(new Uri(user.PhotoLink));
                    set.User = user;
                    return set;
                });
 
            var localFinally = new Action<ParWebLinkSet>(
                (set) => context.Post(
                    (state) =>
                    {
                        var res = (ParWebLinkSet)state;
                        res.User.Photo = GetBitmapImageFromBytes(res.Bytes);
                    }, set));
 
            ParallelLoopResult loopRes = Parallel.ForEach(Users, parOpt, localInit, body, localFinally);
 
 
            Console.ReadKey();
        }
    }
Добавлено через 9 минут
В общем, хочу в нескольких потоках подкачивать изображения в список. Но что-то не пойму, как создать для каждого потока свой WebClient и уже в каждом потоке используя свой WebClient загрузить изображения.

Добавлено через 58 минут
В общем, проблему решил немного по другому. И получил просто огромное ускорение загрузки изображений.

Медленно:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void SomeMethod()
{
    SynchronizationContext context = SynchronizationContext.Current;
    var client = new WebClient();
    client.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
    Task.Factory.StartNew(() =>
    {
        foreach (UserViewModel user in Users)
        {
            byte[] bytesBmp = client.DownloadData(new Uri(user.PhotoLink));
            context.Send((state) =>
            {
                var res = (Tuple<UserViewModel, byte[]>)state;
                res.Item1.Photo = GetBitmapImageFromBytes(res.Item2);
            }, new Tuple<UserViewModel, byte[]>(user, bytesBmp));
        }
    }).ContinueWith((task) => client.Dispose());
}
Очень быстро:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void SomeMethod()
{
    SynchronizationContext context = SynchronizationContext.Current;
 
    int counter = 0;
    Parallel.ForEach(Users,
        (user, pLoopState) =>
        {
            var webClient = new WebClient();
            webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
 
            byte[] bytesBmp = webClient.DownloadData(new Uri(user.PhotoLink));
            context.Post((state) =>
            {
                var res = (Tuple<UserViewModel, byte[]>)state;
                res.Item1.Photo = GetBitmapImageFromBytes(res.Item2);
            }, new Tuple<UserViewModel, byte[]>(user, bytesBmp));
            Debug.WriteLine("{0}) {1}", Interlocked.Increment(ref counter), user.FullName);
        });
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.06.2014, 01:38
Ответы с готовыми решениями:

Parallel.ForEach не компилируется, так как не понятно где ошибка в создании цикла.
public ObservableCollection&lt;string&gt; ObsCollLinksFromFile { get { return obsCollStr; } } Есть цикл: ...

Получение данных из Parallel.For или Parallel.ForEach
Есть некоторый список с исходными данными (данные не зависят друг от друга). Исходя из этих данных необходимо провести некоторые вычисления...

Нужен простой пример из Foreach в Parallel.Foreach
Покажите любой простой пример из Foreach в Parallel.Foreach. Не могу до конца понять.

12
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
14.06.2014, 03:44
Casper-SC, ну заменил считай обычный foreach на Parallel.ForEach. Можешь еще PLINQ попробовать. Может будет быстрее, а может и медленнее. Но слегка поизящней.
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
14.06.2014, 16:09  [ТС]
В итоге всё кончилось этим:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
        public void InitializeData()
        {
            User loginedUser = _vkApi.Users.Get(_vkApi.UserId, ProfileFields.All);
            List<User> friends = _vkApi.Friends.Get(_vkApi.UserId,
                ProfileFields.FirstName | ProfileFields.LastSeen | ProfileFields.Photo100);
 
            LoginedUser = new UserViewModel(loginedUser, friends.Count);
 
            foreach (User person in friends)
            {
                var user = new UserViewModel(person);
                Users.Add(user);
            }
 
            DownloadImages(Users);
        }
 
        private void DownloadImages(IList<UserViewModel> users)
        {
            SynchronizationContext context = SynchronizationContext.Current;
            var photos = new BlockingCollection<Tuple<UserViewModel, BitmapImage>>(users.Count);
 
            Task.Factory.StartNew(() =>
                  {
 
                      var loopRes = Parallel.ForEach(Users,
                            (user, pLoopState) =>
                            {
                                byte[] bytesBmp;
                                using (var webClient = new WebClient())
                                {
                                    webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
                                    bytesBmp = webClient.DownloadData(new Uri(user.PhotoLink));
                                }
                                context.Post((state) =>
                                {
                                    var res = (Tuple<UserViewModel, byte[]>)state;
                                    photos.Add(new Tuple<UserViewModel, BitmapImage>(res.Item1,
                                        GetBitmapImageFromBytes(res.Item2)));
                                }, new Tuple<UserViewModel, byte[]>(user, bytesBmp));
                            });
 
                      while (!loopRes.IsCompleted)
                      {
                          Thread.Sleep(10);
                      }
 
                      return photos;
                  }).ContinueWith(task =>
                  {
                      foreach (Tuple<UserViewModel, BitmapImage> res in task.Result)
                      {
                          res.Item1.Photo = res.Item2;
                      }
                  });
        }
Единственный минус - фотки появляются все сразу и после задержки, но так как качаются параллельно, то происходит это быстрее, чем их качать по одной и выводить сразу. Хотя можно что-то придумать: Разделить на некое кол-во массивов (точнее стуктур ArraySegment<T>) и выводить сразу после скачивания одного сегмента несколько фоток на экран. Я пробовал каждую фотку сразу выводить, но подвисало окно и сразу почти все фотки появлялись.

Добавлено через 3 минуты
Цитата Сообщение от Psilon Посмотреть сообщение
Casper-SC, ну заменил считай обычный foreach на Parallel.ForEach
Так-то оно так, но скачивается уж точно быстрее в разы. Даже если на каждой итерации обращаться к общему ресурсу, выигрыш от распараллеливания никуда не пропадает. Так как скачивание достаточно длительная операция и обращение никак не сопоставимо с задержкой на скачивание одного фото.

Добавлено через 29 секунд
Цитата Сообщение от Psilon Посмотреть сообщение
Можешь еще PLINQ попробовать. Может будет быстрее, а может и медленнее. Но слегка поизящней.
Ну да, я вчера наткнулся на статью:
http://net-prog.blogspot.ru/20... plinq.html
1
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
14.06.2014, 17:49
Casper-SC, спасибо, про AsOrdered не знал.

И еще, разве Parallel.ForEach не является последовательным оператором? То есть цикл вообще не должен ни разу отработать

Насчет фоток - думаю, ничего страшного, если их просто с lock'ом добавлять, а не пользоваться InnerCollection'ом. То есть сразу добавляй в результирующую коллекцию (то есть чтобы после скачки она сразу отображалась). От пары сотен локов хуже не станет - это простой в несколько миллисекунд. Фоновая подгрузка фоток лучше, чем экономия пары мс.
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
15.06.2014, 01:57  [ТС]
Цитата Сообщение от Psilon Посмотреть сообщение
Насчет фоток - думаю, ничего страшного, если их просто с lock'ом добавлять, а не пользоваться InnerCollection'ом. То есть сразу добавляй в результирующую коллекцию (то есть чтобы после скачки она сразу отображалась). От пары сотен локов хуже не станет - это простой в несколько миллисекунд. Фоновая подгрузка фоток лучше, чем экономия пары мс.
Дело в том, что я так и делал и в итоге подвисало окно и сразу же появлялись все скачанные фотки. При том, что если весь код обернуть в Task и в конце ждать завершения всех итераций во всех потоках, то всё нормально работает и грузится. Вот самый нормальный вариант, всё грузитсяв несколько потоков, окно не зависает, вообще работает как я изначально и хотел.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private void DownloadImages(IList<UserViewModel> users)
{
    SynchronizationContext context = SynchronizationContext.Current;
 
    Task.Factory.StartNew(() =>
        {
            var loopRes = Parallel.ForEach(Users,
                (user, pLoopState) =>
                {
                    byte[] bytesBmp;
                    using (var webClient = new WebClient())
                    {
                        webClient.CachePolicy =
                            new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
                        bytesBmp = webClient.DownloadData(new Uri(user.PhotoLink));
                    }
                    context.Post((state) =>
                        {
                            var res = (Tuple<UserViewModel, byte[]>)state;
 
                            var tuple =
                                new Tuple<UserViewModel, BitmapImage>(res.Item1,
                                    GetBitmapImageFromBytes(res.Item2));
 
                            tuple.Item1.Photo = tuple.Item2;
 
                        }, new Tuple<UserViewModel, byte[]>(user, bytesBmp));
 
                });
            while (!loopRes.IsCompleted)
            {
                Thread.Sleep(10);
            }
        });
}
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
15.06.2014, 05:47
C#
1
2
3
4
while (!loopRes.IsCompleted)
{
    Thread.Sleep(10);
}
Это лишнее. Parallel.ForEach выполняется синхронно, в смысле ждет завершения выполнения всех распаралеленых задач.
Tuple тоже можно убрать.
1
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
15.06.2014, 05:55  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Это лишнее. Parallel.ForEach выполняется синхронно
Кстати, да. Только проверил, выполнение дотуда доходит после завершения, короче, эта конструкция вообще не срабатывает

Добавлено через 46 секунд
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Создание Tuple тоже можно убрать.
Да этот код редактировался фиг знает сколько раз, что-то просто забыл убрать/изменить

Добавлено через 2 минуты
Тогда уж выложу исправленную версию.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private void DownloadImages(IEnumerable<UserViewModel> users)
{
    SynchronizationContext context = SynchronizationContext.Current;
 
    Task.Factory.StartNew(() =>
        {
            Parallel.ForEach(users,
                (user, pLoopState) =>
                {
                    byte[] bytesBmp;
                    using (var webClient = new WebClient())
                    {
                        webClient.CachePolicy =
                            new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
                        bytesBmp = webClient.DownloadData(new Uri(user.PhotoLink));
                    }
                    context.Post((state) =>
                        {
                            var res = (Tuple<UserViewModel, byte[]>)state;
                            res.Item1.Photo = GetBitmapImageFromBytes(res.Item2);
                        }, new Tuple<UserViewModel, byte[]>(user, bytesBmp));
 
                });
        });
}
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.06.2014, 20:06
Цитата Сообщение от Casper-SC Посмотреть сообщение
Кстати, да. Только проверил, выполнение дотуда доходит после завершения, короче, эта конструкция вообще не срабатывает
я же написал это тремя постами раньше >_<

что касается остального, то явно какое-то недопонимание. Ты качаешь параллельно? да. Почему ты не можешь сразу же после скачивания в том же потоке, в котором скачал, добавить фотку? А ля
C#
1
Parallel.ForEach(users, u => picturebox1.Image = GetPicture(u));
Добавлено через 59 секунд
Хотя ты это вроде как и делаешь через контекст. Хочешь сказать, не работает?..
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
15.06.2014, 20:07  [ТС]
Цитата Сообщение от Psilon Посмотреть сообщение
Ты качаешь параллельно? да. Почему ты не можешь сразу же после скачивания в том же потоке, в котором скачал, добавить фотку? А ля
Потому-что нельзя присвоить BitmapImage, который был создан не в том же потоке, в котором находится UI

Добавлено через 36 секунд
Цитата Сообщение от Psilon Посмотреть сообщение
Хотя ты это вроде как и делаешь через контекст. Хочешь сказать, не работает?..
После метод Post весь код выполняется в том потоке, в котором был получен этот объект контекста.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.06.2014, 20:39
Casper-SC, ну так понтяно, что я говорил про UI контекст:
если так лучше
C#
1
Parallel.ForEach(users, u => Dispatcher.Invoke(()=>picturebox1.Image = GetPicture(u)));
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
15.06.2014, 20:41  [ТС]
Цитата Сообщение от Psilon Посмотреть сообщение
Casper-SC, ну так создай в UI-потоке, проблем-то
А я что делаю?

Добавлено через 1 минуту
Цитата Сообщение от Psilon Посмотреть сообщение
если так лучше
Чем лучше? Меня вполне использование контекста устраивает. Им можно и перенаправлять события в поток создавший класс, который что-то делает в другом потоке. Аля BackgroundWorker, не вижу никаких причин вызывать методы Dispatcher'a
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.06.2014, 20:41
Casper-SC, ну тогда при скачке просто он в контексте основного потока должен выполнится, но никак не должно получиться, что они одновременно все появятся (если только одновременно все потоки не завершились).
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
15.06.2014, 20:42  [ТС]
Цитата Сообщение от Psilon Посмотреть сообщение
Casper-SC, ну тогда при скачке просто он в контексте основного потока должен выполнится, но никак не должно получиться, что они одновременно все появятся (если только одновременно все потоки не завершились).
Это было из-за того, что я сам Parallel.ForEach вызывал в основном потоке, а сейчас запихал в таск, всё давно уже нормально работает.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.06.2014, 20:42
Помогаю со студенческими работами здесь

Parallel ForEach
Доброго времени суток. У меня сложилась следующая задача: нужна была параллельная обработка очереди, я её реализовал, но есть проблема в...

Parallel.Foreach
привет. решил ускорить существующий код и воспользоваться Parallel.Foreach. итерирую объект DataTable подобным образом ...

Распараллеливание. Parallel.ForEach
На данный момент выполняется такой код: Hashtable files2copy; void startButton_Click(object sender, RoutedEventArgs e) { ...

Parallel.ForEach в цикле
Добрый день. Возникла проблема с написанием небольшого WPF приложения. В C# новичок и с потоками только знакомлюсь. Имеется бесконечный...

Использование Parallel.ForEach
Доброго дня! Появился такой вопрос: написал метод для перемножения матриц, в котором использую Parallel.ForEach. Однако конкретно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru