Прямо праздник какой-то - каждый новый выпуск. Да ещё зимой обычно много праздников... Главное, чтобы у автора энтузиазм делиться своим опытом не пропадал. Я уверен - его жизненная карма обязана при этом становиться лучше. И его английский каким-то волшебным образом тоже.
Просто отличный урок. Кстати, всем, кто найдет это видео уже спустя много лет после публикации (2014). Обратите внимание на комментарий Джона Скита (Aug 18 '15 at 11:22) к своему же ответу: stackoverflow.com/questions/13429129/task-vs-thread-differences?answertab=active#tab-top Т.е. сейчас (в наши дни) рекомендовано использование Task.Run.
Спасибо за урок. Познавательно. То что искал. Но осталось пара вопросов, хотя они м.б. были рассмотрены позднее. Многопоточность с Invoke. Ну как бы вопрос с содержимым кнопки "Отмена" отпал сам собой там и правда только _worker.Cancel(); Так вот: 1. Для чего в тексте форме после инициализации строки: button1.Click += button1_Click; button2.Click += button2_Click; ???? С ними нажатие на кнопку старт запускает сразу два потока. И у многих, как и у меня, возникла проблема с остановкой потока, он и прерывался и продолжал выполняться дальше. Решение Закомментировать или удалить эти строки. 2. Никто не пробовал закрыть форму (Главный "Красный" поток) до завершения синего, пока ProgressBar не заполниться? Вылетает законное исключение. Как отловить это исключение, точнее как остановить Синий вспомогательный поток при остановке главного Красного?
Насчёт ситуации c прогресбаром в 16:16 : может это происходить из-за того, что к тому моменту когда вылезает окно операции по отрисовке( непосредственно рендерингу) ещё не успели выполниться до конца или не выполнился весь стек команд на отрисовку ?
Ролик отличный, жаль отсутствует ссылка на код. Есть немного неточностей: 17:00 Добавили строчку " progressBar.Value = progress + 1; ", но тогда в цикле при i = 100 условие i
Здравствуйте. У меня чёт не работает :) Вот как работает эта система: в классе есть функция Work(), которая вызывает Action "ProgressChanged" с параметром, который (Action) в свою очередь связан c функцией worker_ProcessChanged, производящую манипуляции с прогресс баром. И вызывая функцию класса Work() вызывается worker_ProcessChanged через Action. Я сделал так же: я создал функцию OpNLoad, принимающая на вход OpenFileDialog (он объявлен глобально и определяется по нажатию кнопки). Затем создал Action с тем же типом принимаемого параметра (OpenFileDialog) tryOpen. Далее в нажатии кнопки до определения потока присвоил tryOpen += OpNLoad. Также создал ещё функцию StartLoad, вызывающую Action tryOpen с параметром OpenFileDialog, определённый при нажатии кнопки, и передаю эту функцию (StartLoad) в поток. Структурно всё также, как в видео (на 11:35), функция вызывает Action, связанный с другой функцией, и первая функция передаётся в поток, но всё равно ругается на то, что идёт манипуляция с элементом, созданном в другом потоке (ругается всё также на прогресс бар). UPD: посмотрел дальше и объявил новый Action, который в теле выполняет действия, затем вызвал это действие через Invoke. На прогресс бар уже не ругается и всё загружает, но всё равно не могу двигать формой в процессе загрузки
Посмотрел видео. Начинающим будет довольно сложно понять. Недостаточно разжевано... Вот тут яснее - habrahabr.ru/post/232169/ Но за видео спасибо! Хорошая работа!
Поясните, пожалуйста, почему в синхронном коде у нас зависает форма при работе приложения, а при использовании SynchronizationContext не зависает. Ведь в обоих случаях мы используем один поток (красный). А еще не понятно зачем нужна проверка InvokeRequired. Что происходит если форма решит что не надо делать Invoke? Мы никогда не попадем в наш метод, но мы же хотим туда попасть!
+Yuriy Smirnov 1. При синхронном коде приложение занято выполнением рабочей операции, и из-за этого ему "некогда" реагировать на действия пользователя. Отсюда зависание формы. 2. Обратите внимание: если Invoke не нужен, то операция вызывается, как обычно, не через Invoke. Т.е. значение прогрессбара в любом сценарии будет увеличено.
+Программирование - это просто, спасибо за ответы. Вот еще пара вопросов, если можно. 1. Правильно ли я понимаю, что первый и главный поток это SynchronizationContext который сам запускает поток (второй) для WinForms. Мы передаем наши рабочие операции в главный поток и они выполняются как бы "над потоком" формы. Иначе не понятно за счет чего используя SynchronizationContext мы избегаем блокировки. Если второго потока нет, то программа выполняется линейно. Доходит до рабочей операции и должна "повесить" форму. 2. Не заметил else, извиняюсь, сглупил. Но так ведь еще хуже: операция вызывается не через invoke, значит должно произойти перекрещивание потоков?!
+Yuriy Smirnov 1. Главный поток всегда один. Он циклически опрашивает форму, но внутри цикла так же выполняется и рабочий код. Если рабочий код длительный, то естественно что форма "замораживается", потому что главный поток занят выполнением рабочей задачи и опрос формы останавливается. SynchronizationContext - это по сути список делегатов, который тоже находится в этом цикле опроса. Если мы вынесем долгую рабочую операцию в другой поток, а из этого другого потока будем помещать делегаты в этот специальный список, то алгоритм главного потока будет примерно таким: а) опросить формы (реакция на действия пользователя, изменение внешнего вида) б) выполнить короткий рабочий код, если он есть (длинный то мы вынесли в другой поток) в) выполнить делегаты в списке SynchronizationContext (и тут-то происходит изменение прогресс-бара, появление сообщений об окончании работы и т. д.) 2. Если invoke не нужен, значит, поток один и никакого перекрещивания не происходит )
На WPF метод Invoke(action) следует заменить методом Dispatcher.Invoke(action) Проверку можно осуществить через вызов метода Dispatcher.CheckAccess() который проверяет есть ли у вызываемого метода доступ к потоку (или просто CheckAccess() == false) Таким образом если доступа нету вызываем метод Dispatcher.Invoke(Action callback): if(!CheckAccess()) Dispatcher.Invoke(action); else action();
Здравствуйте, у меня такая проблема. Когда я закрываю форму, (попробовав в закрытии вызвать метод отмены), то выбрасывается исключение - Доступ к ликвидированному объекту невозможен. Имя объекта: "Form1"." Как можно с этим бороться? Заранее спасибо. Пробовал окружать Invoke условием if (this.IsDisposed == false) { this.Invoke(action); } Но почему-то не срабатывает
А как можно передать сам контрол в обработку метода из под другого потока? например метод public void AddRowsDgw(DataGridView Dgw). У меня не получилось это сделать, но сделал некий велик, внутри потока создаю такой же контрол и потом при выходе метода из копии контрола выдаю данные и свойства во внешний контрол не из потока. Может как нибудь по другому можно обойтись ? )
Я не понимаю почему вы на 19:18 пишите this.InvokeEx(action); это же эквивалентно Form1.InvokeEx(action); если я не ошибаюсь. Нам же нужно обращаться к статическому методу класса ControlHelp, тобиш ControlHelp.InvokeEx(this, action);
Код в примере постоянно эволюционирует - показываются различные в том числе и ошибочные варианты, поэтому конкретного кода для урока здесь иногда не бывает... И в этом уроке почти всё показано, кроме создания объекта _context: SynchronizationContext _context = new SynchronizationContext(); в форме.
Defazze Не знаю. Может у меня код другой, _context без типа данных - это ведь просто идентификатор. У меня он подсвечивался красным, создал объект с одноименной ссылкой - всё скомпилировалось... Не важно.
Я один заметил, что перед тем как вызывать событие, его нужно проверить на null? Т.е. что у нас есть подписчики. Т.к. если их нет а мы вызовем без проверки, будет исключение. У автора ролика я этого не увидел.
Что за пример для задротов? Нахрена такие сложные примеры, нахрена этот класс в обучении, нахрена усложнять простое. Типичное неадекватное обучение как в школе, интерес пропадает сразу
Прямо праздник какой-то - каждый новый выпуск. Да ещё зимой обычно много праздников... Главное, чтобы у автора энтузиазм делиться своим опытом не пропадал. Я уверен - его жизненная карма обязана при этом становиться лучше. И его английский каким-то волшебным образом тоже.
7:31 Thread
12:41 Invoke
19:31 SynchronizationContext
Это лучший видеоурок по потокам.
Просто отличный урок.
Кстати, всем, кто найдет это видео уже спустя много лет после публикации (2014). Обратите внимание на комментарий Джона Скита (Aug 18 '15 at 11:22) к своему же ответу: stackoverflow.com/questions/13429129/task-vs-thread-differences?answertab=active#tab-top
Т.е. сейчас (в наши дни) рекомендовано использование Task.Run.
Спустя 6 лет
отличный канал, организаторы уроков молодцы! искал именно в подробнастях. Спасибо!
Очень хорошо - лаконично, ничего лишнего!
Спасибо огромное! Целый день парился. А тут все по полочкам.
Спасибо за такие каналы как ваш! Очень полезная информация!
С первого раза понял про многопоточность. Браво автор
Хорошее описание, все четко и по делу!
Спасибо за урок. Познавательно. То что искал. Но осталось пара вопросов, хотя они м.б. были рассмотрены позднее.
Многопоточность с Invoke.
Ну как бы вопрос с содержимым кнопки "Отмена" отпал сам собой там и правда только _worker.Cancel();
Так вот:
1. Для чего в тексте форме после инициализации строки:
button1.Click += button1_Click;
button2.Click += button2_Click;
????
С ними нажатие на кнопку старт запускает сразу два потока. И у многих, как и у меня, возникла проблема с остановкой потока, он и прерывался и продолжал выполняться дальше. Решение Закомментировать или удалить эти строки.
2. Никто не пробовал закрыть форму (Главный "Красный" поток) до завершения синего, пока ProgressBar не заполниться? Вылетает законное исключение.
Как отловить это исключение, точнее как остановить Синий вспомогательный поток при остановке главного Красного?
Как же долго я искал именно такой урок. Спасибо вам большое!!!
Большое спасибо за урок!
На моей предыдущей работе все разработчики тоже говорили "шедУлер". Так по-родному звучит ))))
Отличный урок. Спасибо.
Спасибо, очень подробно!
Очень круто! Большое спасибо!
Браво! Спасибо за урок!
Спасибо, понравилось!🙂
именно то что я искал, спасибо большое !
Спасибо, отличный урок.
Очень доступно! Спасибо
Насчёт ситуации c прогресбаром в 16:16 : может это происходить из-за того, что к тому моменту когда вылезает окно операции по отрисовке( непосредственно рендерингу) ещё не успели выполниться до конца или не выполнился весь стек команд на отрисовку ?
Вспомнился фильм "Охотники за привидениями".) "Нельзя скрещивать потоки!" =)
хорошиее видео подробное у вас получаеться все понятно
Спасибо!
вот щас бы про MVC посмотреть)
ASP.NET MVC это вообще интересная тема. так что буду ждать
Ролик отличный, жаль отсутствует ссылка на код. Есть немного неточностей:
17:00 Добавили строчку " progressBar.Value = progress + 1; ",
но тогда в цикле при i = 100 условие i
Круто. Tasks бы с async\await действительно не помешал)
Будет в следующей части )
Большой вопрос: нажимая кнопку стоп messageBox выводится, а вот progressBar не останавливается и доходит до конца. Почему так?
Супер
Здравствуйте. У меня чёт не работает :)
Вот как работает эта система: в классе есть функция Work(), которая вызывает Action "ProgressChanged" с параметром, который (Action) в свою очередь связан c функцией worker_ProcessChanged, производящую манипуляции с прогресс баром. И вызывая функцию класса Work() вызывается worker_ProcessChanged через Action.
Я сделал так же:
я создал функцию OpNLoad, принимающая на вход OpenFileDialog (он объявлен глобально и определяется по нажатию кнопки). Затем создал Action с тем же типом принимаемого параметра (OpenFileDialog) tryOpen. Далее в нажатии кнопки до определения потока присвоил tryOpen += OpNLoad. Также создал ещё функцию StartLoad, вызывающую Action tryOpen с параметром OpenFileDialog, определённый при нажатии кнопки, и передаю эту функцию (StartLoad) в поток.
Структурно всё также, как в видео (на 11:35), функция вызывает Action, связанный с другой функцией, и первая функция передаётся в поток, но всё равно ругается на то, что идёт манипуляция с элементом, созданном в другом потоке (ругается всё также на прогресс бар).
UPD: посмотрел дальше и объявил новый Action, который в теле выполняет действия, затем вызвал это действие через Invoke. На прогресс бар уже не ругается и всё загружает, но всё равно не могу двигать формой в процессе загрузки
Вряд ли. Если что и будет, то ASP.NET MVC
+Defazze Так где же ASP.NET? У вас очень хорошие уроки, с удовольствием смотрел бы серию асп.нет мвс.
может вернетесь с курсом по asp.net Core
Оператор лилии Брик
А какой код в кнопке Stop? (На видео не показано).
UPDATE: Разобрался, там _worker.Cancel();
у меня все равно не работает , progressBar не останавливается (((
Почему-то после остановки процесса он продолжается, хоть и выходит окно с ошибкой. Из-за чего может быть?
Defazze, кол-во просмотров растет. В след видео вставь номер кошелька. С мира по нитке, а тебе приятно.
А будет ли рассмотрен паттерн MVVM, как это было с MVP?
Посмотрел видео. Начинающим будет довольно сложно понять. Недостаточно разжевано...
Вот тут яснее - habrahabr.ru/post/232169/
Но за видео спасибо! Хорошая работа!
Поясните, пожалуйста, почему в синхронном коде у нас зависает форма при работе приложения, а при использовании SynchronizationContext не зависает. Ведь в обоих случаях мы используем один поток (красный).
А еще не понятно зачем нужна проверка InvokeRequired. Что происходит если форма решит что не надо делать Invoke? Мы никогда не попадем в наш метод, но мы же хотим туда попасть!
+Yuriy Smirnov
1. При синхронном коде приложение занято выполнением рабочей операции, и из-за этого ему "некогда" реагировать на действия пользователя. Отсюда зависание формы.
2. Обратите внимание: если Invoke не нужен, то операция вызывается, как обычно, не через Invoke. Т.е. значение прогрессбара в любом сценарии будет увеличено.
+Программирование - это просто, спасибо за ответы. Вот еще пара вопросов, если можно.
1. Правильно ли я понимаю, что первый и главный поток это SynchronizationContext который сам запускает поток (второй) для WinForms. Мы передаем наши рабочие операции в главный поток и они выполняются как бы "над потоком" формы.
Иначе не понятно за счет чего используя SynchronizationContext мы избегаем блокировки.
Если второго потока нет, то программа выполняется линейно. Доходит до рабочей
операции и должна "повесить" форму.
2. Не заметил else, извиняюсь, сглупил. Но так ведь еще хуже: операция вызывается не через invoke, значит должно произойти перекрещивание потоков?!
+Yuriy Smirnov
1. Главный поток всегда один. Он циклически опрашивает форму, но внутри цикла так же выполняется и рабочий код. Если рабочий код длительный, то естественно что форма "замораживается", потому что главный поток занят выполнением рабочей задачи и опрос формы останавливается. SynchronizationContext - это по сути список делегатов, который тоже находится в этом цикле опроса. Если мы вынесем долгую рабочую операцию в другой поток, а из этого другого потока будем помещать делегаты в этот специальный список, то алгоритм главного потока будет примерно таким:
а) опросить формы (реакция на действия пользователя, изменение внешнего вида)
б) выполнить короткий рабочий код, если он есть (длинный то мы вынесли в другой поток)
в) выполнить делегаты в списке SynchronizationContext (и тут-то происходит изменение прогресс-бара, появление сообщений об окончании работы и т. д.)
2. Если invoke не нужен, значит, поток один и никакого перекрещивания не происходит )
спасибо, Бро :)
Суппер, +++
На WPF метод Invoke(action) следует заменить методом Dispatcher.Invoke(action)
Проверку можно осуществить через вызов метода Dispatcher.CheckAccess() который проверяет есть ли у вызываемого метода доступ к потоку (или просто CheckAccess() == false)
Таким образом если доступа нету вызываем метод Dispatcher.Invoke(Action callback):
if(!CheckAccess())
Dispatcher.Invoke(action);
else
action();
Где бы скачать исходник этого урока?
молодец
спасибо )
Здравствуйте, у меня такая проблема. Когда я закрываю форму, (попробовав в закрытии вызвать метод отмены), то выбрасывается исключение - Доступ к ликвидированному объекту невозможен.
Имя объекта: "Form1"."
Как можно с этим бороться? Заранее спасибо. Пробовал окружать Invoke условием if (this.IsDisposed == false)
{
this.Invoke(action);
} Но почему-то не срабатывает
то, что надо.
Скажите пожалуйста, будет ли разсмотрен вопрос отладки многопоточных приложений?
не планировал.
@@Defazze не написали код обработчика события нажатия второй кнопки
Почему не показали код в баттоне Стоп? Мне лично любопытно как остановить поток.
private void butStop_Click(object sender, EventArgs e)
{
if (_worker != null)
_worker.Cancell();
}
почему то у меня ProgrerssChanged выдает null reference exception
А как можно передать сам контрол в обработку метода из под другого потока? например метод public void AddRowsDgw(DataGridView Dgw). У меня не получилось это сделать, но сделал некий велик, внутри потока создаю такой же контрол и потом при выходе метода из копии контрола выдаю данные и свойства во внешний контрол не из потока. Может как нибудь по другому можно обойтись ? )
Не надо создавать контролы не в основном потоке. Это оборачивается гигантским количеством проблем.
Ничего не понял, но очень интересно)
Я не понимаю почему вы на 19:18 пишите this.InvokeEx(action); это же эквивалентно Form1.InvokeEx(action); если я не ошибаюсь. Нам же нужно обращаться к статическому методу класса ControlHelp, тобиш ControlHelp.InvokeEx(this, action);
Потому, что это расширение. Обратите внимание на урок "Три Кита". Где-то во второй половине урока автор расказывает о преимуществе даного подхода.
Лайк.
Можно проще:
Invoke((Action)(() => { /* Действия в главном потоке */ }));
"As soon as you type new Thread(), it’s over, your project already has legacy code" - Concurrency in C# Cookbook, By Stephen Cleary.
про кнопку стоп то не рассказали ))
а я на есемблере всего 30 строк вся многопоточность ))) занимает
Когда будут новые уроки 7
Сергей Коваль Скоро
извините, а неужели сложно выложить и исходники?
По мне так вариант с invoke - очень стрёмное решение с т.з. архитектуры приложения
Напоминает свёртку в линейной алгебре. (x, f) => f(x), где x in L, f in L*.
Плиз выложите на дробокс или гугл драйв примеры.
Код в примере постоянно эволюционирует - показываются различные в том числе и ошибочные варианты, поэтому конкретного кода для урока здесь иногда не бывает... И в этом уроке почти всё показано, кроме создания объекта _context: SynchronizationContext _context = new SynchronizationContext(); в форме.
София Солнцева как это не показано, 21:33, обработчик MainForm_Load )
Defazze Не знаю. Может у меня код другой, _context без типа данных - это ведь просто идентификатор. У меня он подсвечивался красным, создал объект с одноименной ссылкой - всё скомпилировалось... Не важно.
Автор жлобяра, исходник зажал!
Станьте моим учителем) по с#
Ребят как называется библиотека xakep.ru/2010/08/10/52926/ ?
У меня не возникло исключения после создания потока))
люди, код бросьте в коомент, пожалуйста!
Я один потерял инициализацию _context?
Не один
а что в C шарп многопоточность есть ? интерестно а в бейсике есть ?
срэд
Автор неужели так сложно выложить исходник?
Ни_я непонятно. !!!!
Я один заметил, что перед тем как вызывать событие, его нужно проверить на null? Т.е. что у нас есть подписчики.
Т.к. если их нет а мы вызовем без проверки, будет исключение. У автора ролика я этого не увидел.
Дослушал до места "брик".
Отличный урок. Спасибо. Но произношение у автора английского просто ппц. После того как он скедъюлер назвал шедулером я чуть не умер))
AbelardoTV шедьюлер - английский вариант, скедьюлер - американский (или наоборот)
Что за пример для задротов? Нахрена такие сложные примеры, нахрена этот класс в обучении, нахрена усложнять простое. Типичное неадекватное обучение как в школе, интерес пропадает сразу
Руслан Баскунов прост уроки не для аутов, что и сказано в описании канала.
А чо там сложного ?? пара эвентов если смутила так это база без её знания смысл смотреть это видео стремиться к нулю
форму создал, а дальше переписывать с видео не стал, автор жлобяра, мог бы и поделится исходником!
молодец