0: Так, прошу прощения, у нас тут были проблемки с записью нашей сессии. То есть сейчас должно быть все хорошо, сейчас я вам расскажу. Вернёмся к моему рассказу.
1: И вообще бенефиты, то есть что мы получаем от использования тпл, мы получаем
2: Демо корсар.
3: Более эффективное использование ресурсов, более масштабируемое использование ресурсов системы и более точный контроль над нашим приложением, нежели при использовании сре или work item, как в случае с обыкновенными потоками либо пула потоков.
4: Хотя на самом деле тпл и таски использует у себя внутри пул потоков и сами потоки, но об этом мы поговорим чуть позже тпл была введена в версии дотнета, 4 0 располагает.
5: System Рединг, таск на спейсе. Если вы заметили, что в вижуал студии 12 и выше, этот немспейс у нас добавлен автоматически. И здесь же располагаются следующие классы, которые наиболее интересны. На мой взгляд, это task.
6: Потом таск резалт, то есть типизированный класс Тасков, таск, фектори, сам класс, который позволяет нам как бы конструировать наши таски и статический класс.
7: Parallel то есть сегодня мы, в частности, затронем класс таск резалт и класс параллел.
8: Класс result это основной класс. Я бы так сказал, что этим классом мы пользуемся больше всего из всех классов, тп. Он имеет следующие члены в себе конструктор.
9: 1 из перегрузок, которого принимает делегат, который будет возвращать результат нашего нашей таски. На самом деле конструкторов там очень много, если я не ошибаюсь, там больше 10 конструкторов этого таска. Но вот это самое часто используемое, то есть обыкновенный конструктор, который
10: Понимает, что же надо выполнить у класса таск есть статическое свойство фектори, которое как бы предоставляет доступ к методам фабрики, которая будет создавать наши таски.
11: Непосредственно создавать наши таски. На самом деле свойство фектори, она нам досталась по наследству от обыкновенного класса. Таск. Ну из task result мы тоже можем вызвать и как бы проблем с этим не будет. Id свойство кото
12: Возвращает id нашего таска, если вы помните, у средов есть нечто подобное.
13: Result, это свойство, присущее только классу дженерик. Ну то есть task result, это свойство позволяет нам получить результат выполоты. То есть, если мы отправили на вычисление там любую функцию, какую-нибудь там сумму,
14: Введение чего-либо. Обратившись к свойству резалт, мы сможем получить результат выполнения этой работы. Это свойство не так просто, как может показаться на 1 взгляд. То есть просто обратившись к нему, мы результат
15: Получить не сразу. Это связано с тем, что как бы, во время доступа к свойству за, ну, резалт, мы можем резулт может быть ещё не вычислен. И в данном случае мы получим ситуацию как обыч.
16: Weit, то есть наш поток, которому необходимы результаты вычисления, просто будет ждать, пока эти результаты будут получены.
17: Вот свойство статус. Стоит ещё отметить, что, result, если в момент обращения к этому свойству результаты были уже вычислены. То есть основной поток поток, который запрашиваете этот результат, останавливаться не будет, он сразу полу.
18: Результат и получит дальше дальнейшую обработку. Статус, свойство, статус позволяет нам получить
19: Статус нашего таска, то есть может возвращать такие значения, как статус таск может быть отменён, он может быть создан, но не запущен, как в случае с средами. Там тоже есть такое состояние, когда мы вроде создали наш сред, но он ещё как бы не рабо.
20: Task может быть прерванным например из за необработанного исключения и 2 как бы основных часто используемых статуса это task может быть завершён и task может быть в процессе выполнения.
21: Есть ещё пара статусов, но они настолько редки, что я их даже упоминать не буду. Как бы на моей практике я не встречал эти статусы на практике, но если вам будет интересно, можете зайти на мсд.
22: И посмотреть, какие же члены предоставляют нам таск, статус перечисления.
23: 1 из методов, который нам предоставляет класс таск Ризат, это continue, из который принимает в себе делегат action, вот который принимает в себя другой.
24: Task. Данный метод позволяет нам выстраивать цепочки вызовов, которые должны выполняться асинхронно. То есть мы создаём 1 наш таск, запускаем его на выполнение. Вот
25: А к нему потом вызываем метод континиус и передаём ещё 1 туда таск. Таким образом, наш 2 таск, который стоит 2 в цепочке вызовов, запустится непосредственно после завершения выполнения нашего 1 та.
26: Что позволяет нам выстраивать довольно громоздкие и длинные цепочки вызовов наших тасок. При этом сам код, который как бы создаёт всю эту цепочку, инстанцирует эту цепочку и запускает её на выполнение, продолжит выполняться и при
27: Необходимости может получить результат самого последнего звена в цепочке.
28: Вопрос зачем контини из action task, а не просто таск. Дело в том, что метод контини он не может знать, а как же завершился наш предыдущий?
29: Task предыдущее звено в цепи, и данный как бы делегат, который принимает таск, позволяет нам как программистам, предусмотреть подобные варианты и написать 2 звено в цепочке таким образом, чтобы покрыть все возможные кейсы.
30: Task может быть отменён, может быть просто как бы прерван по каким-либо причинам, либо результаты не соответствуют там и прочее, прочее, прочее вот и принимать делегат не просто таск на самом деле в большинстве случаев для каких
31: Бизнес задач. Сам объект таска нам и не нужен. Во 2 звене, как минимум, нам нужен только, ну, в большинстве случаев результат выполнения 1 таска. И имея как бы action, который будет принимать в себя этот таск, мы сможем как бы
32: Описать тело нашего 2 звена, которое будет принимать объект task. То есть 1 наше звено, например, обращаться к свойству резалт, получать это значение и обрабатывать его как, как нам необходимо вообще.
33: Так, посмотреть я не вижу смысла, зачем передавать там ещё 1 туда таск. Хотя я уверен, что 1 из перегрузок будет принимать просто таск, который, то есть, ну, там уже будет другая конструкция, там будет таск, который принимает другой таск. То есть это
34: Несколько сложнее конструкция. Ну вот это 1 из перегрузок континью иис. На самом деле их там тоже, по моему, около 10 перегрузок континью иис и есть generic и не generic реализация метода континью иис.
35: То есть и 1 часть она 1, как 1 набор методов континиус будет использоваться для неё дженерик реализации класса таск.
36: Я надеюсь я ответил на ваш вопрос и мы пойдём дальше. Ну и 2 как бы наиболее узнаваемых метода это старт, который позволяет как бы непосредственно запустить наш, наш таск на выполнение и wait, который говорит, что метод, который вызывает
37: Этот метод wait на каком-то конкретном таске будет ожидать завершения выполнения.
38: Сразу бегу несколько вперёд, есть ещё метод таск wait all это статический метод, который принимает в себя массив тасок и этот метод будет ожидать завершения всех переданных в него.
39: То есть порой это весьма необходимая вещь.
40: Итак, почему же все-таки мы должны использовать таски? Почему не треды? Операция по созданию треда весьма затратная операция по созданию потока, весьма затратная операция, как говорил вчера Лёша, к тому.
41: Тому же, если мы создаём большое количество потоков и запускаем их на выполнение, то будет теряться довольно большое время на переключение контекстов, как бы и мне кажется.
42: 2 весьма существенных минуса. Но давайте сейчас посмотрим, как же таски решают эти проблемы. Я уже говорил, что таски внутри себя используют пул потоков. И вот именно благодаря пулу потоков эти 2 Зада
43: Решаются. Как говорил Лёша, пул потоков избавлен как бы в большинстве случаев от необходимости постоянного создавания новых потоков. Тем самым мы решаем 1 проблему, мы постоянно не создаём новые потоки, а просто
44: Загружаем задачу на выполнение. Вот и 2 проблема контекст че он тоже решается пулом потоков. Правда, частично пул потоков обрабатывает все наши запросы на выпол, на параллель.
45: Выполнение некоторой работы таким образом, чтобы по возможности уменьшить число переключений контекстов. То есть, если нам все de переключение контекстов необходимо по каким-либо причинам, там наши все потоки уснули там или
46: Ещё что-нибудь тогда он переключает, но если такой необходимости нету, контекст переключаться не будет.
47: Вот давайте немножко посмотрим на то, как же мы создаём
48: Поток, то есть здесь небольшой фрагмент кода, как вчера показывал Лёша, то здесь мы создаём обыкновенный тред и запускаем его на выполнение, как бы все довольно примитивно.
49: А давайте посмотрим, как же тоже самое, но будет написано с использованием тасок. То есть мы обращаемся к статическому свойству фектори у класса таск и вызываем метод start new. Передаём ему делегат в качестве именно той джобы, которую он
50: Мы не хотим выполнить параллельно, при этом мы, как можете заметить, отдельно метод start не вызываем, то есть через метод фабрики старт нью мы создаём и запускаем сразу же. Даже не так будет правильнее сказать. Создаём и ставим в очередь.
51: Выполнение нашу Таску, так как у нас под нашими тасками есть пул потоков, то он не может постоянно запускать все потоки на выполнение и вот start new он ставит эту очередь и при 1 1 освободившемся потоке в пуле.
52: Потоков наша джоба начнёт выполняться.
53: Вот давайте попробуем визуализировать, что же на самом деле происходит в случае с редами. То есть у нас, предположим, у нас есть ситуация, что мы собираемся выполнить 2 параллельных действия, и оба этих действия будут
54: Делать большое количество вычислений. При этом мы будем использовать одноядерный процессор. То есть мы создаём 2 объекта, трёт и запускаем их. То есть как же будет у нас выполняться. То есть сперва на обработку поступит 1 поток, следующим шагом будет переклю
55: Включение контекстов, то есть контекст поменялся и только потом начал выполняться 2 поток. Потом он отработал выданное ему время. Опять у нас переключение контекстов. Опять мы обрабатываем 1 поток, опять переключение контекста.
56: И опять мы обрабатываем 2 поток. И так до тех пор, пока эти оба потока не будут выполнены, как бы, и вот все эти переключения контекстов они будут занимать, могут занимать довольно приличное время, порой даже соизмеримое с работой, с временем выполнения самих потоков.
57: Вот, а как же это будет выглядеть ситуация с тасками? То есть мы запускаем 2 таска, соответственно, и 1 поступает на выполнение, но когда он своё время отработал и когда приходит
58: Время как бы поменять, ну то есть выдать новое время другому потоку этого не происходит. И этот таск продолжает выполняться за это ответственный пул потоков. Он смотрит, что как бы, пусть он закончит работу, и потом мы возьмём обрабатывать 2, при этом переключение контекста не происходит только
59: Потом у нас поступит 2 поток, и он закончится. Вот. И вот этих 3 переключений контекстов у нас не происходит. Как мы можем видеть вот из этого скриншота я потом запущу этот код вре.
60: Которое мы выигрываем на использовании Тасков, а не средов, может быть порядка 6 раз быстрее.
61: Вот это как бы этот фрагмент, этот скриншот был взят с компьютера, с a7 с гипертрейдингом. И в итоге вот мы получаем, что наши треды выполняются в 6 раз медленнее, чем таски.
62: Вот хорошо, раз уж так используют пул потоков, тогда как бы логичный вопрос, который мы получаем, это, а почему бы сразу не использовать пул потоков? Ш. Показывал, что мы можем это делать. Но почему мы это не делаем?
63: Давайте взглянем на то, как же мы будем создавать задачу на выполнение в пуле потоков. То есть мы обратимся к статическому свойству.
64: Тредпул будем вызывать метод кью ворк, айтем и передадим метод и do some work.
65: Вот как бы все хорошо, то есть все лаконично, всего 1 строчка довольно читаема. А что же, если нам придётся выполнить некую более сложную задачу? Например, дождаться выполнения этой задачи? То есть данный код уже будет
66: Выглядеть не так красочно и потребует от нас дополнительных действий. В частности, нам нужен какой-то, чтобы мы могли знать, а когда же наша джоба выполнилась?
67: Тут вопрос по поводу твоего прошлого примера, Максим, засекал ли ты время выполнения или создания в том числе?
68: Там засекалось время и создания, и выполнения. Я чуть позже покажу вам этот пример. На нём мы ещё немножко можем поэкспериментировать, но я покажу вам этот пример. Вот посмотрим, сколько на данной машине он будет выполняться, во сколько мы получим выигрыш. Вот
69: Я показывал вам, что довольно примитивная задача. То есть нам надо дождаться выполнения некого работы, которая выполняется в параллельном потоке. То есть и тредпул справляется с этой задачей, но весьма как бы
70: Неуклюже, я бы сказал, а треды, простите, таски делают это весьма и весьма как бы элегантно. Я что сказал. Вот простейший пример, как мы создаём таски и запускаем его, передаём ему некий делегат двор и запускаем на выполнение все.
71: Довольно просто. Нам надо запустить несколько и дождаться всех. Не вопрос. Мы вызываем старт ню, передаём в каждый некий метод, а потом вызываем тол, и мы ждём с данной точки. Мы ждём, пока все эти 3 таска отработают, и только.
72: Потом мы продолжим выполняться. Вот надо построить что-то более сложное, какую-нибудь цепочку вызовов не вопрос создаём 1 тред, вызываем у него, простите, таск, вызываем у него континьюс и передаём какому-нибудь вор, и он уже будет выполнять
73: Нечто другое, то есть которое и это нечто другое будет выполняться непосредственно после завершения нашего 1 таска.
74: Вот мы можем пойти ещё дальше и посмотреть на более реальные кейсы, которые встречаются довольно часто. То есть цепочка вызовов. То есть там надо запустить вызов, какую-то цепочку вызовов, неких методов, которые должны выполняться непосредственно
75: После друга, но мы не можем знать, сколько каждый метод из этих будет выполняться.
76: Вот данная цепочка как бы состоит из 4 звеньев. То есть мы создаём новый поток, который загружает картинки из фликера. Вот 2, 2 поток, 2 таска будет именно иска.
77: По результатам, которые мы получили из 1 потока. Вот 3 таска, она запустится только после, когда мы получим результаты поиска, она как бы запостит все это на фейсбук. Ну, 4 таска может разослать всем.
78: Друзьям, например, что типа, окей, я запостил там картинки, придите, полайкайте и при этом наш основной поток. Вот последняя строчка wait, как бы она работает несколько по другому. В данном случае, что мы ждём, как бы таска, кото
79: Здесь и нету в данной цепочке, и мы просто ожидаем как бы некую параллельную Таску, которая выполнялась где-то в другом. Возможно, это какой-нибудь long run operation, который ожидает, когда же там все мои друзья получат конфир.
80: Вот подожди, тут вот несколько вопросов в чате накопилось в чем отличие таск ран от task фектори старт нью.
81: Ещё раз, ещё раз. В чем отличие создания таска с помощью вызова таск ран и task фектори старт нью.
82: А я не уверен, что есть такой метод run, такой метод есть насколько я помню, дело в том, что вот фектори, когда мы через factory создаём новую.
83: Фигурировать настройки самого таска каким-либо образом и использовать эти настройки для того, чтобы создавать набор Тасков, ну одинаковых как бы, грубо говоря, с одинаковыми каким-то характеристикам.
84: Когда используется таск ран, используется фектори по умолчанию, то есть дефолтовая фектори. Вот, ну и для создания нового таска, то есть
85: В случае с factory мы можем создать несколько фабрик Тасков, по разному их настроить и потом создавать новые таски с помощью метода start new и ну как бы таким образом мы будем получать разные наборы Тасков ран ещё раз.
86: Повторюсь, использует дефолтовую фектори.
87: Вот ещё 1 вопрос правильно ли я понял, что задачи и пул потоков решают проблему переключения контекстов тем способом, что просто не переключают, перетасовывают код задачи, то есть по факту они выполняются последовательно.
88: Они параллельно.
89: Не совсем так. То есть как бы он выполняет все это параллельно, но у него есть 1 оговорка, что если самой системой, то есть самой машиной, на которой ты выполняешь, необходимо переключить контексты, то есть потоки упали.
90: Потоки в дедлоке в каком-нибудь, то есть когда как работает вообще пул потоков, то есть он у него есть некий как бы набор свободных потоков, которые он может как бы забиндить на выполнение. Если их не хватает, он их создаёт новые, но вот этот меха
91: Механизм, который как бы создание нового и как бы запуска его на выполнение, он там есть немножко магии, которая вот как бы при необходимости переключит контекст 1 из замерших потоков, которые уже были запущены на выполнение
92: И начнут выполнять какой-то новый поток, который только что поступил. То есть мы не можем гарантировать, что пул потоков однозначно избавит нас от переключения контекстов. Но мы можем однозначно сказать, что все, которые потоки будут выполняться, они будут выполняться после параллельно, простите, и они
93: О какой последовательности не будет идти речь, как я вчера рассказывал, пул потоков при необходимости, при большом количестве задач в очереди может создавать новые потоки для того, чтобы распределять по вновь созданным этим.
94: Потоком задачи из очереди, то есть полностью от переключения контекста, мы не можем избавиться, да, но в то же время, вот посмотрите, если у нас довольно редко поступают задачи на выполнение параллельные
95: То, может быть там достаточно 1 или 2 потоков, уже созданных и для полного обслуживания этих поступающих задач. То есть в этом случае у нас поток выполнит задачу, вернётся в пул, выполнит задачу, вернётся в пул.
96: Ну, вместо создания каждый раз нового потока, это сэкономит довольно большое количество ресурсов. Вот ещё 1 вопрос. Ну, или уточнение по поводу примера, наверное, последнего имеется ввиду.
97: Вот, не могу понять, они просто последовательно работают. Вот, наверное, имеется ввиду по последнему примеру, где фектори старт нью контини контини.
98: Если касса последнего примера, то я, наверное, ответ будет правильным. И да, и нет, если копнуть чуть глубже, то таски работают на самом деле не только на пуле потоков там ещё есть.
99: У них такой диспетчер, координатор, я бы сказал, который уже именно занимается управлением вот всем этим, то есть связью между тасками. И в данном случае у нас все таски одновременно встанут в очередь, но будут попадать в пул они
100: Только как бы после того, как вот этот диспетчер нам скажет, ага, тот таск выполнился. Давай-ка твоя очередь. Сейчас они как будут выполняться последовательно, но они могут выполняться на разных, ну то есть, на
101: Параллельных потоках вовсе. То есть смысл вообще таких цепочек в том, что если у нас есть некий, не знаю, флоу выполнения или обработки данных, например, мы его просто выстраиваем как цепочку вызовов и запускаем и при этом
102: Наш код, который запускает все эти цепочки, может продолжать работать дальше и только при необходимости затребовать результат выполнения этой цепочки не надо постоянно там где то кто-то, чтоб было ещё какая-то 3 сущность, которая будет, не знаю, отслеживать выпол.
103: Каждого из этих потоков и запускать следующий только по результатам предыдущего. Это уже все сделано из коробки. И мы просто выстраиваем как бы вот наш процесс, то есть что и зачем и чего мы ожидаем, каких результатов. И вот этот самый диспетчер, как
104: Он уже все это за нас сделает. Тут ещё такой момент, что, как Максим говорил, континиус имеет множество перегруженных вариантов, которые в том числе позволяют, например, по разному отрабатывать в случае, если таска
105: Фейлился или же, наоборот, успешно завершился. То есть в зависимости от того, как закончилась предыдущая задача действовать тем или иным способом. Так далее. Вот тут уточнение по поводу такран.
106: Factory просто на самом деле ещё раз скажу таск фектори старт нью, то есть здесь используется на самом деле экземплярный метод типа task фектори, который позволяет нам создавать набор однотипных
107: Задач, да, то есть метод таск ран, ну, статический метод таск ран, он использует дефолтовые фектори, который находится в свойстве таск фектори, статическом свойстве. Поэтому, да, то есть task run и task фектори старт нью
108: Это, в принципе одно и то же.
109: Вот ещё какие-нибудь вопросы, пока мы не пошли дальше.
110: Ну, раз нет вопросов, тогда пойдём дальше, а потом перейдём к примерам и попробуем что-нибудь сделать. Такое параллельное, следующее на повестке дня это статический класс. Пара это ещё 1 из составляющих, та лайбер.
111: И этот класс содержит по своей сути всего 3 статических метода. 1 метод фор, как бы, аналогия обычному. Фор форич тоже аналогичная, как бы, то есть.
112: Стандартному ключевому слову и method invoke там очень много перегрузок, которые принимают различные параметры, там можно проходить цикл по по 1 сорсу, по 2 сорсам, там с ключами, со значениями, то есть там перегрузок для каждого из этих методо.
113: Порядка, не знаю, больше 10 то есть в итоге этот класс разросся там, по моему, около 50 методов всего у него. Вот, и как бы смысл всех этих методов в том, что он будет бежать по целевой коллекции
114: Частности, фо фо рич и выполнять вот этот самый action, вот этот вот самый action, который здесь, и вот здесь вот для каждой сущности, в целевой коллекции, но при этом это будет делаться.
115: Умным образом. То есть если у нас, скажем, есть коллекция из 4 элементов и мы выполняем наш код на машине с 4 ядрами, то обработка каждого элемента этой коллекции будет происходить как бы параллель.
116: На разных ядрах. Если же в момент выполнения этого кода наш, наша система понимает, что у нас в системе нет 4 ядер, например, или количество наших ядер меньше количества элементов целевой
117: Коллекции. Наши элементы будут обрабатываться как бы поочерёдно. То есть этот метод будет разбрасывать наши элементы коллекции по разным потокам и количество этих потоков не будет превышать количество ядер.
118: Нашей системы.
119: Method invoke, он позволяет просто выполнить некий набор действий тоже параллельно, то есть здесь в
120: Как бы целевой коллекции служит коллекция неких действий, которые нужно выполнить параллельно. Здесь у нас как бы абсолютно любая коллекция в методе форич, но for это обычный обычный цикл, то есть какие-то есть Инты и вот action,
121: 32. В 1 случае он и будет, должен быть некое действие, которое будет принимать вот этот наш индекс массива от 1 параметра до 2.
122: Так, давайте посмотрим небольшой пример. У нас есть некоторые элементы коллекции, некая коллекция элементов. И если нам хотелось проделать некоторые действия над каждым элементом из этой коллек,
123: Лекции, то, что бы мы сделали, мы написали бы обычный Фрич по некой коллекции и вызвали бы этот процесс так над каждым элементом этой коллекции как бы довольно очевидное решение. Используя метод паралл, мы можем сделать вот
124: Так, использовать метод foreach, передать ему коллекцию. И наш метод процесс, который будет как бы выполняться на каждом элементе коллекции. По сути код делает одно и то же. Но если посмотреть на результаты, которые мы получим в результате 1 или 2 метода,
125: У нас будет почти в 4 раза этот код опять же выполнялся на четырехядерном процессоре. То есть и мы получаем, что используем. Foreach в 4 раза ускоряет нашу, наш код. Вопрос что
126: Что произойдёт, если коллекция будет изменена до окончания обработки, стандартный for each пробрасывает ошибку в этом случае, как действует параллел фор ич.
127: Будет абсолютно тоже самое. То есть это уже ошибка не какой-то параллельной обработки, а это именно ошибка самого нумератора. То есть мы получим абсолютно ту же самую ошибку.
128: И ещё такой вопрос, что в данном случае представляла, ну, коллекция, по которой выполняется параллель фор ич, в данном случае это не важно. То есть, это может быть коллекция цифр, может быть, не знаю.
129: Из базы данных абсолютно что угодно. Это может быть тот же самый массив каких-то действий и процесс будет принимать это действие и, скажем, логировать начало и конец от выполнения этого действия. То есть это может быть абсолютно что угодно. Главное как бы требование, чтобы это
130: Была некая коллекция, а то есть по чем можно гулять? Если это будет некое дерево, то как бы, я думаю, тоже это возможно, но это как бы будет не, ну то есть не обычное поведение цикла фо, например, но при соответствующем итераторе даже по дереву можем вызвать форич.
131: Ещё 1 вопрос. Если попытаться изменить элемент коллекции, изменения же будут вне другого контекста. Ну, наверное, имеется ввиду, если какой-то из элементов коллекции, из элементов коллекции мы какие-то данные там поменяли, то отразится ли это на
132: Параллельные задачи.
133: Тут вот надо рассмотреть как бы 2 ситуации. То есть мы можем запустить на обработку некую коллекцию параллельно. И скажем так, если наш объект был изменён до тех пор, пока он был обрабо,
134: То есть до тех пор, пока он попал как бы вот в этот процесс и попал в пул потоков для обработки. То есть, когда он попадёт, он будет обрабатываться уже с обновлёнными данными. В другом же случае, если как бы мы уже начали обрабатывать.
135: То тут зависит от того, а с каким типом данных мы все же работаем, если мы работаем какими-нибудь велью, тапами, то сколько бы ты там что, не изменял, как бы ты, то есть объект уже захватился и как бы он будет обработан в случае же, какими
136: Reference тапами. Здесь ситуация будет аналогичная, то есть как бы некого рейс кондишена тут не будет и все будет обработано как с обычным объектом. То есть просто считай, что твой метод выполняется где-то параллельно, если ты изменяешь
137: В своём главном потоке и ты работаешь с этим же самым объектом в параллельном потоке. То есть зависит от того, как бы, кто 1. То есть, если тот метод, скажем, скопировал значение какого-то свойства к себе и начал обрабатывать с ним, и ты только после этого начал его изменять, то как бы
138: Будет обработана старая, в противном случае новая, ну то есть это обыкновенная обработка свойств 1 и того же объекта в разных потоках. То есть абсолютно тоже самое будет поведение.
139: Следующий вопрос а можно как-то получить нотификацию, что обработка всех элементов завершилась для случая? Параллель форич? Смысл всех этих методов? Параллель форич в том, что в точке их
140: Вызова мы ждём.
141: То есть это не значит, что мы запустили на выполнение некий массив и действия для для каждого элемента этого массива и пошли дальше. Нет, просто в этой точке мы будем ждать выполнения всех, всей всего этого кода. То есть как бы можно считать
142: Что если у нас в коллекции, скажем, есть, не знаю, 10 элементов, то, вызвав метод foreach, foreach, мы запустим 10 тасок на выполнение, а в конце мы увидим Вейтол.
143: То есть в этот же, то есть только после того, как мы завершим, эта строчка кода завершится, мы как бы, мы уже получим, то есть мы уже будем знать, что-то есть код наш выполнится.
144: Коллекция имён файлов для открытия и обработки, много инпут, аутпут операций. Как обстоят дела с перфомансом? Будет ли там какой-то Гейн поп?
145: Если я так понимаю, мы с помощью параллели обрабатываем массив имён файлов, а внутри куда-нибудь Лазим.
146: Как бы я не думаю, что вопрос как-то правильно поставлен. Что значит обстоят перфоманс мы получим тот же самый буст в 4 раза. То есть это то есть, ну как бы суть вообще этих методов
147: Parallel. Не в том, чтобы каким-то образом всегда получать ускорение скорости, а в том, чтобы потенциально получать это ускорение, то есть на следующем слайде я вам попробую.
148: Покажу вам 3 графика, которые на самом деле должны раскрыть вообще некую такую магию вообще. В чем же особенность этого класса параллел и зачем вообще его это использовать? Ну, если ответить на твой вопрос, как бы коллекция файлов открыть обработки, много её. То есть мы одновре.
149: Будем как бы открывать 4 операции io на 4 разных файлах и будем с этим работать вот вопрос по db контексту на самом деле дб контекст не стоит использовать совместно с parallel форич.
150: Потому что он не является потокобезопасным. Об этом вы можете прочитать, да, в документации. И, например, если он ещё не был инициализирован, а вы пытаетесь его из разных потоков, ну, закурить данные, то вы получите, исключе.
151: С дб контекстом вы можете работать, используя параллел линк, например, для обработки данных. Это будет более правильно. То есть, когда вы к какому типа
152: Какому-нибудь объекту типа ay april можете экстеншн метод вызвать с parallel и далее уже работать параллельно с вашим керил тут очевидно ещё какие-то
153: Добавление по поводу модификации элементов в коллекциях, которые попадают в parallel форич, да, придётся делать доступ потока безопасным, если вы хотите ещё где-то, ну, в разных потоках менять.
154: Ваш элемент коллекции, то есть придётся добавлять какие-то конструкты синхронизации, как бы, да, но тут стоит вообще задуматься, а какую задачу вы хотите решить? Стоит ли для этой задачи использовать, не знаю, класс параллеле.
155: Главный вопрос, который скажет, а какое решение все же надо применить, дабы получить то, что вы, то, что вам надо, так как бы общее магия класса параллел заключается в том, что в момент вызова
156: Этого метода определяются возможности системы. То есть, в частности, количество ядер и исходя из этой информации, определяется, как наиболее оптимально выполнить работу. То есть, если мы запустим фрагменты кода, которые были на прошлом слайде показаны на Дно,
157: Процессоре. Так, то картина будет следующая. То есть разница в производительности, ну, практически отсутствует. Так, если же мы запустим те же самые фрагменты кода на двухъядерной машине, так ускорее.
158: Производительности, то есть время выполнения будет уже в 2 раза меньше.
159: Ну и, соответственно, на четырехъядерной машине мы получим прирост как бы 4 x. То есть вместо 4 Зайцев мы будем выполнять 1 заяц времени.
160: То есть смысл этого класса, а в том, что он очень умный, то есть он выполняет ваш код параллельно на основании возможностей вашей системы.
161: Вот смысл в том, что используя такие классы методы класса параллел для обработки, для некой параллельной обработки массивов данных. При этом мы точно знаем, мы можем гарантировать, например, при написании нашего кода, что эти данные никак между собой не взаимодействуют. Мы можем
162: Как минимум, потенциально ускорить наш код. То есть один и тот же код, скажем, у разных заказчиков будет выполняться на разных машинах, то 1 может получить, там, не знаю, восьмикратный прирост, другой четырехкратный и так далее, и так далее. Как бы разницу, во сколько мы сказать не можем, но можем.
163: Гарантировать, что если он выполняет там код на самой там слабой машине, то потери перфоманса он не получит.
164: То есть это вот основной плюс этого класса, что он умный и он как бы сам определит, а как же лучше выполнить ваш класс и как вообще возможно выполнить ваш параллельный как бы параллельную обработки ваших данных?
165: Вот.
166: Какие-то вопросы были пояснения от аудитории, что-то насчёт конкурент дикшн. Интересно, как бы в каком контексте это было конкурент дикшн есть такое, безусловно есть.
167: Как бы, ну, это несколько, он предназначен для несколько других задач, я бы сказал, конкурен дикшн, он крут, как бы некоторые задачи он позволяет решать, да, он как бы позволяет. Тратите доступ к словарю.
168: Вот, но я не совсем уверен, как он и в каком контексте было это замечание, чтобы ответить, а помогает ли он или нет.
169: Так, давайте попробуем переключиться на вижуал, студию и немножко пошаманить. Так, где наша вижуал, студия?
170: Так.
171: Вот небольшой пример с тасками, то есть есть
172: Как бы массив каких-то ивентов, то есть абсолютно любых неважно. То есть есть, чтобы для трёкать нашу, наш перфоманс и как бы вот 2 основных как бы, действия, то есть мы бе,
173: По нашему массиву и на каждый элемент этого массива мы запускаем поток, который будет как бы выводить в консоль от 1 до 10.
174: Так, все элементарно. Я использую как бы этот вот мануал ресет, н, слим просто, чтобы, как бы трёкать, что как бы все у нас завершились. То есть это как 1 из вариантов, как б.
175: Дождаться, что наш код завершён, то есть выполнение всех наших потоков, созданных как бы завершено, потому что, как бы в случае с редами альтернативы у нас нет. Так чуть ниже, как бы я как бы восстанавливаю.
176: Их и делаю аналогичное ставками. Так, ну и потом как бы вывожу в консоль результаты, сколько миллисекунд потребовалось на выполнение 1, 1 и той же задачи. Вывод в консоль, как бы номер id, ну стей.
177: То и цифры от нуля до 10, и на сколько на это все потратилось времени. Так, если мы
178: Вот давайте попробуем запустить это все.
179: Так оно на другом экране у нас отобразилось.
180: Так, сейчас попробую перебросить вам сюда консольку. Так, очень много выводов. То есть каждый срет и каждый поток все это выбрасывает. И в итоге так, я не думаю, что буфер тут вместил все.
181: Все наши таски, то есть вверху аналогичные записи вот с редами, то есть имя треда, как бы, и цифры, которые он выводит. То есть все это ведётся весьма параллельно. То есть, как можно заметить, порядка тут нету, то есть
182: Никакого, но мы можем, как бы, мы знаем точно, что каждый созданный наш теск, таск или red просто делает, как бы принтует в консоль от нуля до 10, так и на данной машине, на которой в данный момент выполняю этот код какой длины?
183: Мы получили прирост чуть больше, чем в 2 раза.
184: Есть предложение сначала создать массив Тасков, ой, массив тредов, а потом замерить. Стоп, вотч, как я понял, создадим, да, только потом запустим. Стоп вотч. То есть сначала создать массив.
185: Тредов, а потом запустить то, очевидно, замечание на тему того, что для Тасков у нас немножко другой интервал времени замеряется, то есть не учитывается создание. Может это имелось ввиду?
186: Давайте попробуем по поводу конкурент дикшенери. Там ситуация такая, что как только вы обращаетесь к get нумератор, для конкурент дикшенери выполняется, по сути, слепок того,
187: Состояние, которое сейчас в нём находится. И вы енумерейт этому слепку. Если же в момент нумерации кто-то добавляет элемент в конкурент дикшенери, то на существующие нумераторы это никак не
188: Влияет. Так там. Давайте, как мы это можем?
189: Сделать.
190: Так, это мы сделаем. Ещё 1 цикл for здесь у нас будет
191: И с аккаунт. Так и здесь мы сделаем вот эту штуку.
192: Старт и наш воч мы запускаем только здесь.
193: Так, я правильно понимаю ваш пример? Ну давайте попробуем.
194: Так это лишнее.
195: Вот, как бы прирост тот же самый в 2 раза, то есть постоянный как бы вот запуск этих потоков.
196: Переключение контекста между сотней потоков. Вот у нас в 2 раза получаем выигрыш.
197: Вячеслав, на строку 45. Вы предлагаете старт поместить, но это будет не совсем честно, потому что мы вообще тогда непонятно, что замеряем. То есть мы создаём треды, запускаем их сразу же, а потом запускаем.
198: Watch старт это было бы странно и что мы замеряем, то есть непонятно.
199: Да, то есть эта строчка вот здесь вот сейчас она на своём месте, то есть все как положено. Если же мы будем сравнивать как бы таски с red пулом, тогда опять стоит вопрос, а что же мы будем сравнивать? То есть в чем разница вообще? То есть что именно
200: Разницу чего мы хотим определить? Давайте так поставим вопрос.
201: Вот тут да, как раз в эту тему замечание, что, может быть, следует сравнивать таски с red пулом, а не с редом голым?
202: Так, если таски внутри себя используются, пул, то-то есть мы хотим как-то вот этот наш диспетчер протестировать или что-то есть, что мы хотим определить разницу на чем? То есть производительность будет примерно такая же просто
203: С тасками удобнее работать за счёт того, что вы можете продолжение какое-то задекларировать в зависимости от того, какое значение вернулось делать тот или иной кусок работы.
204: То есть таски это красивая обёртка над тредпулом, с которой удобнее, гораздо удобнее работать.
205: Вот вы говорили, что у Тасков есть преимущество по сравнению с тредпулом, потому что меньше контекст, Свич, по моему, там все же было по сравнению с тредом, если да, память. То есть, если при использовании
206: Голых средов. Мы однозначно попадаем на ситуацию с переключением контекстов. При использовании спула мы уменьшаем количество этих свечей и в некоторых случаях этих свечей вообще не происходит. То есть это как бы
207: При использовании Тасков мы не уходим от переключения контекста мы все мы все ещё все ееще полагаемся на возможности сред пула. Вот ещё какое-то замечание, что на тему того, что может быть как-то убрать вывод в консоль.
208: Потому что это тоже занимает операцию, но на самом деле, как я понимаю, что вывод в консоль есть и в случае треда, и в случае таска, и поэтому это примерно одинаковая работа. То есть, может одинаковое количество символов выводить, чтобы совсем был
209: Честнее, но я не думаю, что это слишком сильно отобразится. Ну тогда давай, давайте уберём вывод, консоль. Предложите альтернативу. Что мы будем делать в каждом потоке или в таске. То есть что, чем занять наш тред?
210: Любую, любую идею сейчас же и проэкспериментируем.
211: Вычислять корень из и и печатать в консоль или не печатать считать факториалы.
212: Ну давайте корень какой-нибудь у нас, так это нам пусть будет.
213: Корень и тот же самый, так да, так пока закомментируем это пригодится, так клавиатура не слушается.
214: Так, тут ещё может быть особенность нашего джита, но это другой вопрос, потому что так как мы не используем результат вычисления Корня, если он Шибко умный, то он может тупо не вычислить.
215: Ну, давайте проверим.
216: Я хочу вас огорчить, ребятки, ситуация ещё хуже.
217: То есть выигрыш очевиден.
218: Ещё удостовериться, что я тут ничего не пропустил. Давайте.
219: Так тот же самый резалт.
220: Так, абсолютно тоже самое. Так, цикл резалт Скерт, цикл резалт Скерт. Так, прошу удостовериться, что
221: Все идентично.
222: Где в данном случае нет, вот у нас создаются треды, вот здесь мы их запускаем и watch начинается только отсюда, то есть start и reset, то есть вот это все не считается.
223: То есть, если ты знаешь пример, как бы как проинициализировать поток, не запустив его, я тебя слушаю внимательно. На самом деле некорректно не учитывать, скажем, время на создание потока.
224: В таких замерах производительности, потому что оно есть. Вот в отличие от Тасков, где пул потоков переиспользует уже существующие потоки и создаёт их только по необходимости, то есть то, что в явном
225: Использовании класса thread надо его создать, это часть его апи и от этого никуда не деться, вам придётся создавать новые потоки и тратить на это время вашего приложения.
226: Лучше выведи там консольку сейчас, где моя мышка?
227: Я вчера говорил, да, вот кто-то говорит, что можно создать и 1 раз потоки они одноразовые. Как только поток отработал, вы его переиспользовать не можете. Пул потоков, в отличие от явного создания потока использования.
228: Его до конца, до полной отработки он помещает в него задачу, но не уничтожает его, то есть поток продолжает висеть просто в состоянии спящем.
229: Ну вот, времена чуть чуть поменялись, но
230: Не намного. У меня есть подозрение, что это все оптимизировал джид и тупо не вычисляет этот корень. Я, конечно, могу ошибаться, но да, если я ошибаюсь, то прирост производительности почти в 100 Зайцев, так что
231: Давайте так выводить не g a result.
232: Так, результат в глобальную переменную присваивать. Ну, плохое плохая идея, потому что
233: У вас множество потоков будет в неё писать, ошибки, конечно, не случится, но в результате вы будете видеть абы что.
234: Конкурент дикшенери. Ну, может быть. Так где моя консолька? Что мы имеем?
235: В 3 раза.
236: Угу. Да, ребята сокрушаются на быстрых задачах явно больше, потому что львиная доля происходит от создания потока. Давайте, слипо, ну, дело в том, что
237: Если вы ещё раз посмотрите на пример, Максим исправил вот таким образом, что само создание потока не учитывается в стоп. Вотче, а вот запуск, конечно же, учитывается. То есть, очевидно, что ещё и сам запуск нового
238: Сейчас, в данном случае я вернул, то есть мы учитываем это, но я могу легко вернуть это назад. То есть. Угу. Для чистоты эксперимента. Так, а закомментируем?
239: Оставим это здесь и раскомментируем это, это закомментируем.
240: Ну так в этом и смысл, а чтобы запускать их уже на как бы на существующих потоках.
241: Запуск это и есть создание, это несправедливо для это ну это не совсем верное утверждение, потому что чтобы использовать thread вам его надо сначала создать экземпляр треда, потом вызвать метод старт.
242: В принципе, для таска можно сделать тоже самое, а можно использовать фектори, который внутри себя создаёт таск и сразу же его Ранит.
243: Если.
244: Да, я не совсем понял 1 комментарий касательно одновременного запуска Тасков.
245: И если, конечно, не юзать red пул.
246: Тредпул можно только тогда надо будет модифицировать как бы создание наших Тасков. Безусловно. Ну тогда мы не будем использовать тредпул. Ну что значит не одновременный одновременный запуск Тасков.
247: Как можно запустить одновременно несколько Тасков?
248: Ну, опять же, тут одновременности в нашем жестоком мире вообще такое понятие не существует, да, то есть одновременных вещей их нет в природе. Вопрос давай.
249: 700.
250: Может, пример этот мы сделаем доступными для вас, и вы будете замерять производительность с методом слип, и как вам душе заблагорассудится. Давайте дальше, наверное, пойдём.
251: Я был замьютить у нас пример, то есть будем умножать матрицы, и в 1 случае мы умножим матрицы обыкновенными циклами for так, 3 матрицы, а во 2 же случае мы будем делать тоже самое.
252: Но с использованием параллел. Так, здесь код по инициализации этих самых матриц. И вот самое интересное у нас здесь вот то есть мы стартуем наш счётчик и выполняем как бы
253: Код по умножению этих 2 матриц пара последовательно, то есть обыкновенными циклами форм и выводим результат перемножения в противном же случае. То есть потом мы делаем тоже самое, но уже с использованием класса
254: У меня как бы нет возможности продемонстрировать сейчас возможность, как оно будет вести себя на разных процессорах, там с 1 ядром, с 2 и с 4, как бы, но если мы запустим данный код на машине, которая
255: Имею сейчас. Так вот наш код аутпут, то, что сейчас ничего не меняется, это происходит вычисление. Вот. И мы видим, что прирост в 4 зайца, то есть
256: И умножение как бы вот последовательно с обычными циклами заняло почти 10 секунд.
257: Не знаю, ну, вроде бы нет. Так, ещё особенность всех этих как бы, измерений, которые вот сейчас мы делаем, они не всегда точны. Вот, то есть
258: Порой бывает так, что одновременно там, не знаю, последовательный перезапуск 1 одних и тех же вычислений будет давать несколько разные пример. Да, возможно, ты прав. Это пример из СМС, но, по сути, он показывает, что использование как бы класса
259: Parallel. Вот в данном случае мы получаем прирост в 4 раза. Если же, даже если мы этот наш код с использованием класса параллел попадёт там, не знаю, на Бабушкин компьютер, то как минимум ухудшений производительности мы не получим, и тем самым наш код
260: Становится более гибким, то есть он позволяет нам как бы подстраиваться под системы, на которой он будет выполняться и как бы в идеальных случаях получать реальный прирост производительности.
261: Вот.
262: Если перейти как бы в класс параллел фо, то мы можем увидеть, что перегрузок тут очень и очень много.
263: Их очень много там и каждый там принимает все больше и больше параметров. Параметры разные. По разному их будут обрабатывать по разному. Будут передаваться наши индексы и так далее, и так далее, и так далее, и
264: Подобная полотна подобное полотно методов будет и для метода foreach, и для method invoke.
265: Не уверен, что он позволит нам повесить систему. Вот, потому что за счёт чего он нам её повесит.
266: Если внутри foreach, мы будем использовать глобальную переменную, то прироста производительности вообще не будет, а будет даже наоборот.
267: Имеется. Ну, для каких целей мы будем использовать глобальную переменную, не совсем понятно.
268: Так тут вот замечание на тему что есть parallel опшенс такая штука.
269: Да, по options это возможность как бы конфигурировать нашу параллельную обработку, и они весьма там такие мощая, да, ты прав. То есть с ними можно реально подстроить наш код, не знаю, более конкретного поведения, которое мы
270: Мы пытаемся достигнуть, а не отдать просто на откуп, не знаю, системе, на которой будет выполняться так глобальная переменная, например, глобальный массив, который мы будем записывать параллельно из каждого потока.
271: В данном случае, возможно, как бы мы получим даже ухудшение перфоманса, безусловно, потому что, чтобы это сделать правильно, нам надо, как бы сделать тредсейф запись в этот глобальный массив.
272: Что может повлечь за собой как бы ухудшение производительности, безусловно, но все вот эти параллельные методы, ну, в частности, методы класса параллел, они как бы не предназначены для подобных задач, они предназначены, чтобы удобно и
273: И весьма как бы гибко копировать и выполнять код, который как бы может свободно выполняться параллельно и не влиять на другой код.
274: Не знаю, там логирование, там, вычисление каких-то квадратных корней, там, не знаю, произведение каких-то вычислений, формул и прочее, прочее.
275: Вот 1 из как бы возможностей. Вернёмся к паралле опшенс, как бы оно позволяет конфигурировать как бы пределы вот нашего сплита. То есть мы можем сказать, а насколько же все же, на скольких все же ядрах
276: Выполнять наш код, то есть нам может потребоваться такая штука, что у нас, допустим, супер мощный процессор там с шестнадцатью ядрами, но мы не хотим, чтобы все 16 ядер в данном случае были заняты вот выполнением этого parallel фор. И, используя паралле опшенс, мы можем огра.
277: Подобную цифру, скажем, давай ты будешь выполнять только на 4. При этом остальные 12 могут, не знаю, быть использованы другими нашими, не знаю, сервисами и прочей логикой.
278: Вот, что ещё, что ещё? Может? Вас что интересует, что на этом как бы все, если есть какие-то пожелания, в примерах вопросы абсолютно что угодно пишите.
279: У нас ещё есть время, так что.
280: Вот от себя скажу, что параллел я использовал, наверное, от силы дважды.
281: Но таски я использую повсеместно.
282: Зачем вообще нужен параллел инвок?
283: Это как бы своеобразный аналог метода фо. То есть в данном случае мы интегрируемся по чему-либо, делаем в зависимости от чего-то вот этого, либо что-то действие, допустим в данном случае мы зависим вот это вот
284: От и которая будет инкрементироваться с каждым циклом метод invoke он как бы позволяет нам не зависеть ни от чего, то есть у нас может быть.
285: Вок в обыкновенном случае принимает как бы парамс экшн массив, то есть массив некоторых делегатов, которые просто надо выполнить, они никак между собой не связаны, ни от каких индексаторов не зависят и они будут просто выполнены.
286: Параллельно. Более того, более того, я даже не уверен, что мы можем гарантировать порядок выполнения этих экшенов.
287: Можно скинуть.
288: Кинуть опыта использования Тасков имеется ввиду асинк авейт асинк по асинк авейт. У вас, во первых, будет отдельно. В дальнейшем лекция тут что именно?
289: Интересует. То есть асинкавейт это все же механизм для выполнения, по большей части ио. Баунд операций, то есть для организации операций.
290: Чтению записи, ну, более эффективного. При этом мы не занимаем поток, который ожидает какой-то поток данных по сети, например, или ещё откуда-то мы его возвращаем в пул, и он может выполнять другие
291: Задачи. Вот, Андрей, Андрей, как бы твоё замечание, да, то есть я дважды всего встречал использование параллел, мне кажется, связано со спецификой, как бы тех, не знаю, областей, где мы
292: Работаем и мне кажется, работаем мы в каких-нибудь, не знаю, математических сферах, или используя постоянно какие-нибудь формулы, там дикое вычисление, то мы чаще бы прибегали к этому классу, потому что он вот он для целей вот какой-то математики, он, не знаю, самое оно, то есть, если
293: Надо вычислить много чего, потом вычислить ещё что-то, а потом как-то эти результаты обработать. Вот класс параллел фо, мне кажется вот то, что надо. То есть именно для этих задач он и был создан по поводу использования практики использования Тасков. Ну, например, у меня
294: Была задача, когда надо было запускать, ну, это было windows win 32. Приложение надо было запускать некий тест на выполнение и, естественно, требования, чтобы юзер интерфейс у меня не
295: Не зависал, да, но при этом, чтоб тест можно было там остановить, поставить на паузу. Для этого я использовал таск, ну, таски управлял ими с помощью конслейшен, токен, Сурсов. Я их
296: Cancel. Например, когда мне это нужно было пример использования практика использования асинкавейт. Ну, на самом деле, сейчас это милое дело использовать асинкавейт, если у вас, например, в стеке технологии есть энтити фреймворк, который
297: Поддерживает асинхронные операции, чтения, записи из базы данных плюс у вас, например, какой-нибудь web api или энвиси, который также поддерживает асинхронность, да, то есть у вас весь стек технологий сверху до низу поддерживает.
298: Асинхронность пожалуйста используйте например не ту лист метод, а Тулис асинк и возвращайте из вашего метода не коллекцию, а task строго типизированный ну то есть тут все.
299: Очень просто. Просто надо понимать, что если вы начинаете где-то использовать асинковый, то скорее всего у вас это все протянется с самого верха до самого, до самого низа. Ну то есть у вас будут везде хвосты типа асинк метод будет помечен.
300: Async внутри у вас будут авейты, вот возвращать вы будете таски и прочее, то есть использование и как бы вот вы подписываетесь на повсеместное использование данных ключевых слов не могу сказать что это
301: Хорошо или плохо? Ну, как бы, если нам это необходимо, то это асинкавейт позволяет нам избавиться от огромного количества головной боли. Если же в случае без синовейт, Дмитрий, да, записи появятся на видео.
302: Далее, как только нам выдадут права на как бы на загрузку этих видео, как только так сразу, то есть request уже в обработке. То есть мы просто ждём вместе с вами. Вячеслав делится примером из жизни.
303: Параллели в системе зарегистрирован инстаграм, юзеры для каждого из юзеров сходить на инстаграм и посмотреть, не добавил ли он пост. Параллель форич пробегает по коллекции из пользователей. Да почему бы и нет. Главное, что
304: Parallel. Не загрузил полностью вашу машину. Если это ваша, скажем, ещё и по совместительству рабочая машина, то есть, в принципе, если у вас слишком много пользователей, у вас каждый, каждый такой обработчик
305: Будет занимать 1 ядро и у вас будет довольно проблематично работать с самим компьютером. То есть, в принципе тогда надо ограничивать аппетит.
306: Так, хороший вопрос про исключения в тасках таски. Это в плане вот чейто вызовов и обработок исключений, они шикарны, я бы так сказал, то есть
307: Если какое-то исключение вылетает где-то нам в нашем таске, то наш код продолжает работать, то есть как бы если в случае с потоками, если падает 1 поток и он как бы не background, то у нас падает все в случае star.
308: Такого не происходит, и это исключение будет поймано самим таском, так скажем, и проброшено наружу, но проброшено будет и хитрым образом. То есть мы получим это исключение только в случае, когда мы обратим
309: Допустим, к результату.
310: То есть, как только мы обратимся к объекту, к нашему таска, то есть зачем-то дай мне результат, дай мне статус, как только мы это сделаем. И если как бы до этого наш таск упал по каким-то причинам исключения там, или он был отменён, это сразу всплывёт наружу.
311: И исключение будет выброшено как будто вот из нашего кода, а не из кода, который выполнился в параллельном потоке вообще. Более того, при использовании чейнов, вызовов, то есть метода контин из мы можем использовать как бы чейн опшен, такие как бы
312: Там не, но там куча параметров, которые позволяют нам как бы управлять цепочкой вызовов. То есть у нас могут быть ситуации, когда мы не просто цепочку выстраиваем, а мы можем выстраивать дерево вызовов.
313: И каждое вот как бы звено в этом дереве будет определять, а в какую же сторону нам идти? Например, мы запускаем 1 таск, и мы хотим, чтобы 1 таск выполнился, скажем, при получении результатов. A2 таск будет выполняться, скажем, если наш, нам не удалось получить эти результаты.
314: Мы это сможем легко настроить с помощью параметров, если мне не ошибает, не изменяет память. Так где мой курсор?
315: Да, есть такая таск, континиус, опшенс, которая там не только они на самом деле, но это одни из них. Давайте таск, фектори, старт нью блин.
316: Что-нибудь.
317: Консоль райт лайн пусть будет white.
318: Так, и 2 параметром мы можем передать консолен токен в 1, в 1 из перегрузок. Есть ещё у нас вещь такая таск криэйшн опшенс, то есть тоже перечисление. Если мы посмотрим, какие есть параметры, то
319: Это уже определяет как бы зависимости между различными тасками. То есть у нас могут быть ситуации, когда 1 таск создаётся другим таском, и вот таск решён, опшенс как бы позволяет задать
320: Отношения между родительским таском и дочерним в зависимости от этого будет различное поведение. То есть я сейчас не буду рассказывать вообще, что и как, каким образом влияет.
321: Но одни из ситуации могут быть такие, что у нас 1 таск запускает кучу других Тасков, и мы можем настроить таким образом, что если 1 из чалдовых Тасков падает, у нас падает все, то есть у нас падает родительский таск, который, следовательно, за собой тянет, все остальны.
322: Порой, как бы с точки зрения каких-то бизнес требований это необходимо. Вот раньше как бы был вопрос о создании Тасков без использования пула потоков. И вот таск криэйшн, опшенс лонган позволяет нам это сделат.
323: Если мы будем использовать вот так, то данный таск будет, не будет выполняться в пуле потоков, а наша фектори создаст его как обычный тред и запустит.
324: Вот, для всех операций это как бы, ну, советуется это делать как бы, по причинам, которые я уже описывал, что таким образом мы не забьём наш пул потоков и отдадим пул потоков, ну, вот именно на операции, которые, как бы, советуются, и как бы
325: Рекомендовано или нам бы хотелось, чтобы они выполнялись быстро, параллельно и при этом как бы никто никого не ждал. Вот, да.
326: У нас есть тут вернёмся к continuous, этот континиус, так что у нас он принимает. Он принимает некую функцию, которая должна принимать наш таск и что-то с ним делать.
327: Абсолютно что угодно.
328: Пусть будет, не знаю ничего.
329: Так.
330: Вот у нас есть такие тасс контешн, опшны, их тут весьма много. То есть пересекаются, используя как бы, флаги. Ну, в общем, у них тоже как бы есть пересечение.
331: Touch тупает, тунайт, чайлд теч и прочее, прочее, прочее. Но нас в данном случае больше интересуют вот эти вот нот нот, он can not, он фатет, эти все континен опшен, они уже будут зависеть от результата.
332: Выполнение нашего 1 таска в цепи. То есть мы можем сказать, что давай ты будешь выполнять этот таск только в случае, когда наш целевой, ну, наш 1 таск, наше 1 звено завершилось неудачно, то есть упало или, наоборот, допустим, выполнять, только если он не
333: Допустим, не fall или наоборот, только если фолт, только если консолт и данные вот как бы данные вот опшен, они позволяют нам выстраивать безумные деревья вызовов наших тасок, то есть только с помощью
334: Этих Тасов, как бы, казалось бы, на 1 взгляд параллельно. И при этом мы последовательно мы можем выстраивать реально сложные бизнес процессы и выполнять абсолютно обыденные задачи как бы параллельно, при этом никаким образом, ну,
335: В большинстве случаев не замедляя не ухудшая производительность нашего приложения.
336: Так, где мой курсор? Так какие ещё были тут вопросы? Вот это что касательно эксепшенов и вообще магии всех этих Тасков? Вот континиус со всеми этими опшен. Это, собственно,
337: Огромный плюс вообще этих тасок над всем остальным. То есть они очень и очень гибкие.
338: Будет ли домашнее задание после завтрашнего тренинга?
339: Да, оно будет, скорее всего, оно будет либо завтра вечером, либо в четверг, но оно будет. Я не уверен насчёт практического, потому что, я думаю, его вам должен будет дать ваш личный ментор.
340: Вот. Ну, я думаю, если вы попросите, он мне откажет.
341: Если я захочу запустить определённое количество задач параллельно, то подойдёт только part four тут стоит как бы пояснить, каких именно задач.
342: Если надо определённое количество задач, параллельно именно определённое, что тебе мешает, как бы это же количество тасок создать, если это какое-то там сложное поведение или взаимодействие между ними, тогда это нужно смотреть. Ну, тут надо именно более предметно подойти к этому вопрос.
343: Ты можешь и право использовать, безусловно ты можешь и foreach использовать, как бы это все up to you, то есть данную задачу. Вот если в общем смысле подойти, то есть запустить энное количество задач, параллельно подойдёт любое из решений, хоть таски, хоть
344: Метод parallel и for foreach подойдёт, более того даже подойдёт не знаю, инвок.
345: Да, можно сделать continue из который выполняет 2 разные операции нато и для note безусловно можно то есть для этого будет как бы не цепочка вызовов давай мы попробуем сделать.
346: Что у нас вот пустой метод будет вызываться на not fall. Так. Но для этого нам надо сделать получить наш таск, скажем, сюда.
347: Так потом на нём вызвать континиус.
348: А потом на нём вызвать какую-нибудь другую Таску, которая будет only fall. В таком случае у нас будет как бы дерево, и эта таска у нас будет нодой, а эти 2 вот контини будут тоже тасками, но они будут как бы ответвлениями от нашего
349: И подобных. Вот, говорю, можно выстраивать безумные цепочки, абсолютно безумные, абсолютно на любой статус, на фолд, канц, прочее, прочее, прочее. То есть именно насколько хватит у вас фантазии.
350: Как работает параллель с эксепшенс, то есть что будет, если где-то в каком-то из параллельном параллельного выполняемого метода упадёт исключение это
351: Исключение пробросится сразу же наверх, то есть и в методе вызова. То есть вот в месте, где мы вызываем Профор, у нас, мы получим вот именно в этой точке исключения. То есть этот вызов этого метода он как бы вызывает его и ждёт сразу же
352: Ждёт результатов.
353: Вот и в этой же точке мы получим это исключение, как только какое-либо исключение выбросится где-нибудь внутри.
354: Вот, не совсем понял обращение к сервисам. Чтобы брать данные, мне нужно ограничить число таких запросов, иначе меня залочит. Ну, вы, например, можете создать параллель инвок и
355: Указать максимальное количество одновременно работающих тредов через параллель опшенс. Вот касательно дедлайна по таскам, как Лёша сказал, что да, надо сдать до начала.
356: Следующего модуля. Но если я правильно понимаю всю эту политику, то наш модуль двухнедельный. Вот, а это значит, что следующий модуль за нашим должен начаться в понедельник и, скорее всего, не позже вече
357: Этого уже с понедельника вы уже должны все сдать. То есть, скажем, во вторник утром уже ничего приниматься не будет. Какой статус возвращает континью вис, если он только для в него пришёл фалте. Ну, тут очевидно, что continue with
358: Если он только для нот фалетт, если у вас случился фалт в задаче, то просто не будет континюэйшен никакого, просто ничего не будет вызвано, никакого статуса не будет. Таск так и не запустится, который на продолжение вы
359: Резервировали вот этот код, вот этот код, скажем так, тут на самом деле всего 3 таска, но выполнятся только 2.
360: Даже даже более того, может выполниться только 1, и то не выполнится. То есть если у нас вот этот исходный наш таск, он падает, либо не, то есть выполнится 1 из этих 2 и что
361: Не мешает. Вот самому 1 Таску, например, зависнуть, заблокироваться. То есть произошёл дедлок, и, соответственно, ни 2, который, ни 2 континюэйшен, ни 1 не будут никогда вызваны, потому что у вас ваш 1
362: Task, он, он не завершился никак. Он, если join, завис, да, да, континиус возвращает объект таска, который вот создан, но не запущен. И метод континьюс сразу же поставит в очередь вслед за этим
363: Да, скорее всего, если ваш исходный таск не завершился, ну, не случился ваш статус, на который вы резервировались, то он так и останется в состоянии незапущенном.
364: Вот так это наше свойство ну состояние криэйт да, наверное будет или waiting Туран?
365: Тура будет.
366: Эти таски, статусы Тасков не отличаются от статусов тредов вот не только по назначению, но ещё и по именам, поэтому это может вносить некую путаницу, но, как мне кажется, используя и то.
367: Другое в 1 и том же как бы проекте, это это гиблое дело, отвечая на вопрос сергея значит, енумерейт вот как только что maksim показывал таск, континюэйшен опшенс не помечен флаговым.
368: Поэтому, так как вы тут в коде написали, в чате, такой код, в общем то невалиден, потому что их нельзя комбинировать через битовые операции.
369: То можно. Ну, тогда он должен быть флагом помечен. Проверь, он помечен. Угу. Ну, раз помечен, да, действительно помечен.
370: Так выполнится ли 2 таск?
371: Выполнится, в любом случае выполнится.
372: Вот, он выполнится по любому, потому что данное пересечение выдаёт все возможные варианты, то есть и независимо от вариантов вот этого, какой бы он не имел, мы по любому проходим вот по этому условию мы либо то, либо то и 2, получается, всегда выполнит.
373: То есть это уже вот то, что так подобное можно сделать, это уже издержки именно битовых флагов, но с точки зрения логики, мне кажется, это не имеет смысл. Если, если это имеет смысл, пожалуйста, приведите пример.
374: Вот я думаю, я не знаю, есть ли у вас там в расписании модуль касательно вот енумов и флагов, или, может это где-то в другом будет затрагиваться, но как бы вот это полезно знать, потому что вот оно.
375: Случае это такая вот конструкция очень часто используется и чаще используется не вот такая противоположная как бы вещи, а именно вещи, которые именно группируют, скажем, он ли он фоллетт или он ли он, допустим, канцел. То есть в таком случае данный будет выполнен и на фоллетт, и на
376: В подобном случае мы будем попадать всегда.
377: То есть что как бы аналогично, если мы уберём это вообще
378: И то я только что сказал ерунду. Вот. И вот если мы вообще ничего не напишем, вот так и наш 1 таск упадёт.
379: То 2 таск не должен выполниться вообще.
380: Там надо смотреть какое дефолтное значение передаётся ему вот как continuous опшен и мне кажется он скорее всего как бы only not for
381: То есть как бы вот это передаётся по дефолту.
382: Вот, если больше нет вопросов, я предлагаю завершаться. То есть, спасибо за внимание. Вот. То есть у нас ещё есть там секунд 30, чтобы написать вопрос, если он все же нет, если нет, тогда вот.
383: На сегодня, мне кажется, все.
384: Result Вейт убивает всю многопоточность.
385: Как бы я не убивать всю многопоточность, потому что, как бы это, это, это издержки. А как иначе получить результат? Ну, то есть обычно обычно так будет сперв.
386: Запускаешь лоран, какую-то операцию на вычисление этого результата, потом делаешь какие-то подготовительные действия для того, чтобы потом обработать этот результат, а потом уже обрабатываешь его, как бы от этого никуда не деться. Ну единственное, что
387: Ожидание результата. Например, если у вас метод асинхронный, то ожидание результата может помочь вот как раз механизм асинкавейт. А что касается Вэй, то вы же не обязательно будете ждать 1 завершение 1 какого-то таска.
388: На самом деле, вы можете ожидать сразу же, там 10, 15 Тасков, тогда многопоточность остаётся, ну, 1 поток, да, у вас как бы ждёт.
389: По любому кто то кого-то будет ждать, ну то есть ты запускаешь такт, тебе нужны результаты, ты будешь сидеть и ждать, то есть
390: Все, всем спасибо за внимание, мы будем закругляться, то есть записи будут загружены. Можете потом зайти и посмотреть ещё раз, если есть какие-то вопросы. То есть готовьте завтра у нас ещё 1 сессия.
391: Увидимся завтр.