Асинхронно как это: Что такое асинхронное обучение – Блог Webinar
Что такое асинхронное обучение – Блог Webinar
Мы продолжаем цикл обзоров, посвященный запуску We.Study — нового виртуального учебного центра от Webinar. Сегодня мы расскажем, что такое асинхронное обучение и когда асинхронный формат может эффективно использоваться в онлайн-образовании.
Что такое асинхронное обучение
Асинхронное дистанционное обучение — формат, при котором контакт между студентом и преподавателем осуществляется с задержкой во времени. Обычно преподаватель готовит и структурирует материалы для изучения заранее, а студенты получают к ним доступ и обучаются, как правило, по свободному графику.
Асинхронное обучение всегда предполагает отсроченность приема информации. Сюда можно отнести чтение учебников, статей, блогов, сайтов, интерактивных презентаций, прохождение электронных курсов, тестов, заданий и упражнений, просмотр записанного видео или прослушивание аудиозаписей.
Принято считать, что при асинхронном формате обучения коммуникация между преподавателем и студентами отсутствует. Это не так: преподаватель и студенты могут общаться по электронной почте или в мессенджере внутри образовательной платформы. В процессе обучения студенты получают не только новые знания, но и обратную связь — от образовательной платформы по итогам тестов или от преподавателя после проверки самостоятельных работ студентов.
Кроме того, встречаются курсы (например, на Coursera), в которых слушатели оценивают домашние задания друг друга. Такую форму обучения также можно считать асинхронной.
В чем особенности асинхронного обучения
Описывая особенности асинхронного формата, удобно разделить их на плюсы и минусы.
Широкая география. Асинхронное обучение доступно для слушателей из любой точки мира.
Гибкость. Слушатели могут самостоятельно выбрать траекторию и график обучения.
Поточность. Для запуска курса необязательно набирать группу — студенты могут начать и завершить обучение в любое время.
Удобство управления. Потратив время на старте, вы почти не тратите время на отдельных студентов.
Дешевизна в процессе. После запуска курса — почти никаких затрат.
Свобода. Когда курс запущен и приносит деньги, можно заниматься чем-то другим — например, запускать новые курсы.
Ответственность. Необходимо подготовить все учебные материалы заранее: это серьезная инвестиция времени и денег на старте.
Затраты на старте. Необходимо купить или арендовать специальную технику и программное обеспечение — например, видеокамеры или платформу для организации обучения.
Неуниверсальность. Асинхронный формат подходит не для всех учебных программ (но об этом — ниже).
Низкая вовлеченность. Студенты должны сами себя мотивировать на обучение и результат. Также нет групповой динамики, которая достигается при синхронном обучении.
Когда эффективно асинхронное обучение
Асинхронный формат подходит для изучения как гуманитарных, так и технических дисциплин — и даже танцев и йоги.
Асинхронное обучение особенно эффективно, если необходимо:
- запомнить много теоретического материала — асинхронный формат позволяет легко возвращаться к пройденным урокам;
- подготовиться к аттестации или тестированию — эксперты считают асинхронный формат наиболее эффективным при подготовке к ЕГЭ или экзаменам в автошколе;
- создать курс для студентов с разным уровнем подготовки — каждый сможет выбрать свой темп и траекторию обучения;
- провести массовое обучение, например, по охране труда и пожарной безопасности, — обучаться в асинхронном формате могут одновременно сотни человек.
В качестве основного стоит использовать асинхронный формат в корпоративном обучении и дополнительном образовании: асинхронный формат — более гибкий, позволяет учиться в удобное время, в любом месте. Синхронное обучение скорее должно выполнять дополнительные функции по разъяснению трудных моментов, повышению мотивации и вовлеченности слушатель в процесс обучения.
Когда неэффективно асинхронное обучение
Асинхронный формат неэффективен, если главное в преподавании дисциплины — приобретение технических навыков или обязательное взаимодействия с преподавателем. К примеру, асинхронный формат не подходит для обучения вождению или игре на гитаре.
Для некоторых дисциплин — например, для обучения иностранным языкам — лучше всего подойдет смешанный формат обучения: асинхронный формат для изучения грамматики и письменных заданий и общение с преподавателем в онлайне для формирования навыков говорения. К примеру, электронный курс можно дополнить вебинаром, в ходе которого устно делается акцент на важных моментах, дается возможность задать вопрос преподавателю, проговариваются проблемные моменты.
Выбирая платформу для организации смешанного обучения, убедитесь, что сможете совместить синхронный и асинхронный форматы в рамках одного курса. Платформа We.Study позволяет вовлекать участников в процесс обучения за счет разнообразных типов занятий — текстового контента, вебинаров, тестов и домашних заданий в единой структуре курса.
Как устроено смешанное обучение?
Что такое смешанное обучение? Почему смешанный формат эффективен? Каковы его практические преимущества? Об этом и многом другом — в обзоре «Что такое смешанное обучение».
Узнайте больше о создании учебных онлайн-программ
Для того чтобы помочь нашим пользователям с проектированием учебных программ, мы создали бесплатный онлайн-интенсив «Онлайн-курс на 100%».
Регистрируйтесь на интенсив, чтобы узнать, как проектировать и создавать учебные онлайн-программы, подбирать контент и использовать инструменты для вовлечения слушателей в обучение.
Все участники интенсива получат бесплатный тестовый доступ к We.Study от Webinar.
Узнайте больше о создании учебных онлайн-программ
Регистрируйтесь на онлайн-интенсив «Онлайн-курс на 100%», чтобы узнать, как проектировать и создавать курсы, подбирать контент и использовать инструменты для вовлечения слушателей в обучение. Все участники интенсива получат бесплатный тестовый доступ к We. Study от Webinar.
Синхронность и асинхронность процессов / Хабр
Мир может многому научиться у программистов. Он и так учится, только не тому и не так. Например, взял процессы и алгоритмы, но не заметил такого подхода, как асинхронность.
Любому программисту понятно, что такое синхронность и асинхронность. Вот насколько это понятно программисту, настолько это непонятно и обычным разработчикам процессов.
Синхронные действия процесса – те, которые выполняются в основном потоке, в рамках одного экземпляра процесса. Ключевое отличие синхронного режима: следующее действие начинается только тогда, когда завершено предыдущее. Соответственно, пока одно действие не завершено, процесс стоит колом.
Асинхронные действия – те, которые выполняются параллельно основному потоку, либо в том же экземпляре процесса, либо вообще в другом процессе. Ключевое отличие асинхронного режима: параллельное выполнение двух и более ветвей процесса.
Синхронные процессы, как и программы, писать и отлаживать намного проще, поэтому такой подход к конструированию процесса очень сильно распространен. С асинхронностью надо много возиться, особенно – с обозначением точек перехода в параллельное выполнение и возврата обратно, в русло основного процесса. В жизни ведь нет промисов.
Например, тот же процесс закупок по заявке. Рисуется стандартно, как последовательность действий: появилась заявка, снабженец выбирает поставщика, запрашивает сроки и стоимость, согласует с продавцом или отделом внутреннего контроля, формирует заказ поставщику, запрашивает в юридическом отделе или в бухгалтерии оценку контрагента, создает заявку на оплату, ждет этой оплаты, отслеживает заказ, потом организует или отслеживает оприходование на складе, чтобы, в конце концов, закрыть заявку. Процесс полностью синхронен.
Теперь представим – в нашей информационной системе не подключен сервис оценки поставщиков. Значит, юридическому отделу нужно собирать информацию из открытых источников. Значит, на выполнение оценки требуется время. С учетом очереди заявок к юристам, пройдет дня три.
Что в это время будет с процессом? Согласно синхронной логике, он будет стоять колом. Снабженец, будучи верным элементом системы, и пальцем не пошевелит, пока не получит оценку поставщика – особенно, если предусмотрены санкции за работу с непроверенными контрагентами.
Можем мы здесь добавить асинхронности? Конечно. В тот момент, когда снабженец выбрал поставщика, он может отправить заявку на оценку контрагента в юридический отдел, а сам пока будет вести переговоры, согласовывать цены и сроки. К тому моменту, когда он будет готов разместить заказ, и оценка подоспеет. Процесс закончится раньше на три дня.
Конечно, юристы могут возмутиться – чего это мы будем оценивать поставщика, если вы там еще четко не решили, будете ли у него заказывать? Что им ответить?
Решение напрашивается само собой, выше мы его уже обозначили – подключить сервис оценки поставщиков. Теперь мы еще лучше понимаем, зачем оно нужно – для придания асинхронности и ускорения процесса. Хотя, сервис, наверное, будет как раз синхронным. Как думаете?
Если сервис не подключать, то можно оправдать такую оценку работой «впрок». Если в вашей информационной системе есть куда записать данные оценки, то в следующий раз, когда возникнет потребность в работе с этим поставщиком, обращаться в юридический отдел уже не придется. Конечно, у оценки есть срок годности, но в некоторых разумных пределах ей пользоваться можно.
В асинхронности обычно пугает отсутствие гарантий, то есть риск негативного результата в одной из параллельных ветвей процесса. Что делать, если согласование закончится неудачей?
Тут нужна статистика. Если вы работаете с существующим процессом, то примерно, или точно, представляете себе, как часто определенные действия заканчиваются негативно – например, согласования. Вот из этой вероятности и стоит исходить, запуская параллельное выполнение.
Асинхронность прям напрашивается во все процессы согласования. Если там работать только по синхронному режиму, да еще и идти на поводу у согласующих, то выстраиваются длинные, взаимозависимые цепочки, порождающие бюрократию и круговую поруку.
Типичный пример: «я буду согласовывать только после того, как согласует вот он». Или «я посмотрю на этот договор только после финансистов». Хотя, если верить статистике и здравому смыслу, подобные постановки не имеют под собой оснований, и являются лишь способом переложить ответственность.
Тут главное – не переживать, и не браться за все сразу. Попробуйте выделить в асинхронный режим сначала одну ветвь согласования. Возможно, потребуется пересмотреть задание, параметры согласования – так, чтобы исключить взаимозависимость.
Например, пусть финансовый отдел, стоящий в цепочке согласования договора, смотрит только на условия оплаты. Пусть у него будут свои, понятные критерии оценки. Лучше, если они будут формализованы в виде типового договора – например, 100% постоплата для поставщиков, 100 % предоплата для покупателей. В таком случае договоры, удовлетворяющие критериям, будут проскакивать на раз. И у финансистов не останется повода ждать оценки от тех же юристов.
Единственное, что важно: асинхронные процессы очень сложно реализовать без автоматизации. Если процессы, их исполнение и отслеживание реализованы только на бумаге, то добавление параллельных ветвей превратит их в хаос. Нужна автоматизация.
Лучше всего для такой автоматизации подходит принцип «Автозадачи». Хотя, можно обойтись и стандартными средствами рисования процессов, которые есть в современных платформах, только придется повозиться.
Стандартные «рисовалки» процессов потребуют от вас обозначить весь процесс, все ветви и взаимосвязи. Если процесс сложный и длинный, то вы столкнетесь с проблемой – он банально перестанет влезать на экран, в ширину. Если вы учились в институте на программиста, то помните такое правило оформления алгоритмов: не более трех параллельных вертикальных ветвей. Правило придумано не просто так – если ветвей будет больше, понять схему алгоритма будет проблематично.
Автозадачи от этой проблемы избавляют – там изображения процесса нет вообще, т.к. отсутствует такая сущность – процесс. Есть задачи. Если очень хочется, можно из них собрать процесс. Но не наоборот. Эдакий дедуктивный метод рисования процессов.
Кроме асинхронности, есть еще более мощный метод оптимизации – буферизация процессов. О нем – в другой раз.
Асинхронное обучение
В мире, где в бешеном темпе развиваются информационные технологии, сеть Интернет и онлайн-пространство, невозможно не заметить изменений, касающихся и сферы обучения. Уже сейчас появляется всё больше и больше онлайн-платформ, удобных для освоения различных специальностей и прохождения курсов, – в том числе и языковые площадки. Они значительно облегчают процесс образования, помогают в повышении уровня языка и при этом выгодно отличаются своей демократичной стоимостью.
Но мир развивается дальше, преобразуя и виды познания. Простым онлайн-образованием уже никого не удивишь, поэтому и появляются всё новые способы освоения материала и даже обучающие тренды. Мало кто знает, что на сегодняшний день онлайн-площадки весьма заинтересованы в асинхронном обучении, которое предполагает максимально самостоятельный подход к получению знаний и является перспективным форматом образования.
Что такое асинхронное обучение?
Асинхронное обучение относится к дистанционному виду образования, когда отсутствует непосредственный контакт между преподавателем и учеником. Процесс проходит не столь быстро, с небольшой задержкой, из-за невозможности личного присутствия. Но это отличный вариант для тех, кто не имеет возможности выезжать за пределы своего места жительства и учиться в тесном контакте с преподавателем.
Асинхронное образование при этом идёт ещё дальше, основываясь на подчас полностью самостоятельной работе ученика. Преподаватель заранее подготавливает материалы и схему обучения, а студент усваивает информацию уже в свободном графике онлайн без интерактивного взаимодействия. Выполненные задания ученик отправляет куратору, который может проверить их спустя некоторое время, то есть процесс обучения проходит в отсроченном формате.
В асинхронном обучении могут использоваться следующие материалы:
- Онлайн-учебники и электронные книги в оригинале – хороший вариант для освоения языка, когда вы можете самостоятельно читать те книги, которые вам интересны и полезны;
- Статьи и блоги, в которых находится самая актуальная информация по необходимой теме;
- Интерактивные презентации, помогающие усвоению знаний;
- Тематические сайты и форумы, способствующие расширению объёма информации и её углублению в заданной сфере;
- Фильмы и подкасты, в которых затрагиваются последние тенденции в области интересующей вас темы;
- Электронные курсы – хороший вариант ещё сильнее углубиться в изучение материала;
- Тесты, задания, упражнения от преподавателя или найденные на тематических ресурсах;
- Специализированные видео и аудио по заданной тематике.
Не стоит считать, что в подобном формате обучения полностью отсутствует общение между студентом и преподавателем. На самом деле коммуникация может осуществляться посредством электронной почты или мессенджера; то есть, изучение материала происходит всё же не в абсолютно одностороннем порядке. К тому же, встречаются и такие курсы, в программе которых заложено общение между студентами.
История возникновения
В начале 19-го века возникло тогда ещё не слишком перспективное заочное обучение, на которое не возлагали больших надежд. Но уже тогда в сферу образования закладывались первые кирпичики дистанционного получения информации, стали появляться обучающие аудио и видео.
С появлением сети Интернет появилась возможность беспрепятственно данную информацию распространять и копировать, сохранять, то есть успешно применять её на деле. Начиная с 1980-х годов информационные технологии стали появляться повсеместно, выводя образовательную среду на новый уровень. Асинхронный способ обучения стал применяться всё чаще.
1990-е годы ознаменовались постепенным смешением разных методов получения образования, и благодаря развитию информационных технологий асинхронный способ стал примечательной сферой обучения. Сегодня данный метод является весьма перспективным и порой заменяет другие форматы изучения необходимых программ.
Особенности асинхронного обучения
Мировой рынок обучения онлайн расширяется невероятными темпами, и его финансовый оборот насчитывает уже более 150 млрд долларов. По прогнозам «Research and Markets», к 2025 году эта цифра достигнет 330 млрд. Всё больше людей склоняются в сторону онлайн-платформ для получения тех или иных знаний. В мире ценится направленность на самостоятельное обучение, особенно важны для рынка труда те специалисты, которые ориентированы на непрерывное образование.
Каждая профессиональная сфера подразумевает постоянное развитие в рамках специальности или за её пределами. Нельзя всю жизнь заниматься лишь одним делом, нисколько не повышая свою квалификацию и не модернизируя области её применения. Концепция непрерывного обучения весьма полезна как для работника, так и для работодателя, а цифровой формат обучения помогает претворить в жизнь постоянное совершенствование и образование.
Как и у любого новомодного формата обучения, у асинхронного имеются свои нюансы:
- Пластичность графика – студент сам выбирает тот режим освоения знаний, который ему удобен;
- Доступность – изучать новые материалы можно из любой точки планеты;
- Единоличность – необязательно записываться в группу для прохождения необходимого курса, график индивидуален;
- Двустороннее удобство – максимальную выгоду из подобных отношений извлекают обе стороны: преподаватель не тратит много времени на одного ученика, имея возможность выбирать претендентов, а студент не расточает энергию на общение со множеством кураторов;
- Бюджетность – онлайн-площадки предлагают на сегодня самые актуальные и низкие цены на обучение иностранным языкам;
- Отсутствие универсальности – не каждому желающему обучиться английскому языку могут подходить условия асинхронного образования, не все программы и базы знаний созданы для этого;
- Низкая вовлечённость – для максимально успешного результата нужна высокая степень ответственности самого студента, способного мотивировать себя на изучение нового материала, следовать графику и заниматься самоконтролем. Не всем это даётся легко.
В каких случаях вам подходит асинхронное обучение
Становится ясно, что данный формат образования имеет свои особенности, которые могут подходить не всем. Стоит понимать, когда подобное обучение сможет принести свои плоды:
- Если вам нужно подготовиться к экзамену в краткие сроки – будут ли это экзамены в автошколе или ЕГЭ, данный формат поможет добиться максимальной результативности в формате тестов;
- Если необходимо запомнить много теоретических знаний – обучающийся имеет возможность повторять пройденный материал столько, сколько потребуется для полного его запоминания;
- Если необходимо обучить максимальное количество учеников с разным уровнем подготовки – здесь не придётся создавать для этого группу и обучать всех разом, каждый студент получает свой материал, что удобно и для них самих, и для преподавателя.
Асинхронное обучение может активно использоваться в корпоративной сфере, когда нужно одновременно поднять уровень большого числа сотрудников с минимальными временными и денежными затратами. В формате дополнительного образования такой способ тоже будет очень полезен и эффективен. Асинхронный вариант обладает нужной гибкостью и свободой, которая зачастую подходит именно занятым на работе или в других сферах деятельности людям.
В каких случаях вам не подходит асинхронное обучение
Исходя из самой специфики данного вида образования, стоит понимать, когда оно не сможет привести к нужным результатам:
- Если требуется прохождение практического материала, при котором важно взаимодействие ученика и преподавателя. Вы не сможете дистанционно обучиться, к примеру, вождению автомобиля или игре на музыкальном инструменте;
- Если для запоминания информации вам требуются наглядные примеры и живое общение с куратором. Так часто бывает при изучении иностранных языков, когда требуется диалог с педагогом или с непосредственным носителем языка. В этих случаях обычно асинхронное обучение дополняется онлайн-беседами, необходимыми материалами для устного изучения.
Преимущества и недостатки асинхронного обучения
Несмотря на особенную популярность подобного метода среди современной молодёжи, у асинхронного обучения есть свои плюсы и минусы, которые стоит учесть перед выбором способа получения образования. Зачастую данный метод либо является дополнительной базой в усвоении знаний, либо идёт бок о бок с другими форматами обучения.
Плюсы:
- Гибкость: студент может выбирать удобный ему график усвоения знаний, из любой точки мира, в комфортное время. Если ученик обладает самоорганизованностью, усидчивостью, а также чётко понимает, зачем и почему ему необходимо это обучение, то процесс однозначно будет проходить эффективно и быстро, а также легко.
- Сокращение затрат, которые больше не включают в себя аренду помещения для обучения и жилья при посещении города, в котором проходят курсы. Стоимость курсов значительно снижается за счёт отсутствия привычных предметов и нюансов для получения образования офлайн.
- Возможность выбирать необходимые дисциплины, составлять собственную схему запоминания и прохождения материала. В этом случае удобство изучения иностранного языка может подойти многим категориям людей, курс становится более доступным для широкого круга студентов, в том числе для зарубежных граждан, занятых на работе или получающих второе образование.
- При помощи современного программного обеспечения и высокоразвитых информационных технологий, используемых в асинхронных курсах изучения языка, можно создавать интерактивное взаимодействие между студентами, даже если они находятся в разных странах, что однозначно помогает более эффективному усвоению знаний, а также расширению кругозора.
- Асинхронное обучение помогает культивировать в себе полезные черты характера, как например, самоконтроль, усидчивость, мотивация. Данные свойства способствуют не только качественному усвоению новых знаний, но и однозначно помогут студенту в дальнейшей жизни.
- Все данные, учебные материалы, записи уроков, результаты тестирований и переписка сохраняются в электронном виде, что помогает более чётко следить за успеваемостью ученика, а также даёт возможность студенту возвращаться к необходимым для повтора заданиям. Это очень удобно, потому что знания не исчезают, записи курса помогают гораздо глубже и основательнее усваивать информацию.
- На основе сохраняющихся данных о способностях ученика преподаватель может корректировать программу обучения, понимая, в какой области есть недочёты и где нужно подтянуть знания студента, а какие этапы можно пропустить. Это очень полезно для более удобного и быстрого обучения, как для самого обучающегося, так и для куратора.
- Происходит индивидуализация обучения, которая в большинстве случаев очень удобна для студентов и позволяет расширять границы своих знаний не только в узкой профессиональной области. Обучающиеся одновременно познают современные технологии, развивают свои когнитивные навыки, а также идут в ногу со временем, не отклоняясь от трендов, а совершенствуясь вместе с ними.
Если верить исследованиям Старр Роксанны Хилц и Стефана Храстински, асинхронное обучение даёт толчок для развития профессионально-личностных качеств в человеке, что однозначно пригодится в будущем. При возможности обсуждения своих идей в рамках изучаемой программы образуется активное взаимодействие с другими участниками, свобода преподнесения информации, её дальнейшее развитие в благоприятной среде.
Исследователи утверждают, что асинхронность помогает повышать уровень мотивации в человеке, что, в свою очередь, способствует более глубокому и скорому запоминанию информации. Работая над заданиями онлайн, студенты обладают большим количеством времени на переработку знаний, обдумывание решений. Получаемое в результате этого взаимодействие с другими учениками развивает в них когнитивные навыки, коммуникационные способности, активизируют мышление.
Минусы:
- Организовать асинхронное обучение непросто, для этого требуются значительные временные затраты: преподавателю нужно заранее создать всю необходимую базу информации, материалы и упражнения, а также организовать возможность дистанционной коммуникации с учеником;
- Перед студентами так же возникает задача обзавестись подходящими для получения подобного образования технологиями: компьютерами, средствами связи. Это и установка определённых приложений, и получение навыков пользования компьютерными технологиями, также здесь понадобятся навыки самостоятельного поиска информации;
- Для обучения по данной программе требуется большая усидчивость и мотивация студента, что не всегда представляется возможным или является довольно трудным для ученика.
Тем не менее, эти проблемы в большинстве случаев решаемы, поэтому асинхронный способ обучения является действительно перспективным и подходящим многим методом получения образования.
Перспективы развития асинхронного обучения
Онлайн-обучение на сегодняшний день становится всё более и более популярным способом получения образования. Это и удобно, и эффективно, а также весьма перспективно. По данным «Ambient Insight», рынок онлайн-образования каждый год вырастает на 5%. Таким образом, уже через пару лет он постепенно начнёт вытеснять офлайн обучение. Это актуально как для корпоративной сферы, так и для общеобразовательной.
Также результаты некоторых исследований говорят о том, что цифровые технологии становятся более эффективными в рамках получения образования, нежели традиционные. Уже на сегодняшний день во многих учебных заведениях используются интерактивные тесты, видео, игры для лучшего усвоения информации.
Перспективы дистанционного обучения таковы, что по некоторым прогнозам они в скором времени переместятся в виртуальную реальность. Пока многие организации сторонятся введения информационных технологий в свою систему работы, некоторые крупные компании начинают внедрять VR в рабочий график и получать в этом плане внушительные результаты. Повсеместного распространения VR пока, конечно же, не стоит ожидать, так как это весьма недешёвое удовольствие, но в перспективе данный метод будет крайне востребован. За информационными технологиями и онлайн-обучением стоит будущее.
Все права защищены. При копировании материалов сайта, пожалуйста, обязательно укажите наш ресурс — www.accent-center.ru
Асинхронное и синхронное обучение: что выбрать?
Все кто организует дистанционное онлайн обучение (неважно корпоративное или академическое) очень часто сталкиваются с необходимостью выбора формата.
Все виды обучения (и онлайн, и оффлайн) можно разделить на две большие группы: синхронное и асинхронное. Деление это основано, как видно из названия, на синхронизации приёма и отправки информации между субъектами и объектами взаимодействия. Если попросту, то синхронное обучение — это когда приём и передача информации происходят практически одновременно. Сюда можно отнести лекцию, вебинар, популярные ныне прямые эфиры в социальных сетях, чаты. То есть инструменты, при помощи которых слушатель (читатель) получает информацию сразу же и имеет возможность задать вопрос или выполнить задание преподавателя.
Асинхронное обучение предполагает отсроченность приёма информации. Сюда можно отнести чтение учебников, статей, блогов, сайтов, интерактивных презентаций, прохождение электронных курсов, тестов, заданий и упражнений, просмотр записанного видео или прослушивание аудиозаписей.
Понятно, что выбор средств всегда должен быть связан с учебными целями, однако это только в теории. На практике же организаторы онлайн обучения чаще всего руководствуются не целями, здравым смыслом или научными знаниями, а своим опытом и привычками.
Так синхронный формат более привычен и понятен для большинства представителей поколения, рождённого до цифровой эпохи, либо тем, кто слабо разбирается в новых технологиях. Кроме того, синхронный формат предпочитают люди с преобладанием черт экстравертов.
И наоборот, учить и учиться, выбирая асинхронный формат, предпочтитают представители поколения digital. Такие люди меньше настроены на социальное взаимодействие в классическом смысле. Им проще бывает написать, чем рассказать словами, прочитать или послушать запись, посмотреть видео, чем присутствовать на лекции. У них есть свой собственный темп приёма и передачи информации.
Использование только синхронного или асинхронного обучения приводит к снижению эффективности. Например, люди, предпочитающие свой собственный темп, или те, кому нужно живое общение для усвоения информации, будут очень по-разному воспринимать один и тот же учебный контент.
Идеальным решением, безусловно, будет совмещение или параллельное использование обоих форматов. К примеру, электронный курс дополняется вебинаром, в ходе которого устно делается акцент на важных моментах, даётся возможность задать вопрос преподавателю, проговариваются проблемные моменты.
Классическое академическое обучение обычно предлагает синхронный формат (лекцию) как основной, а асинхронный как дополнительный. Этот же принцип чаще всего пытаются перенести и на прочие обучающие мероприятия, например, корпоративное обучение и дистанционные курсы.
При этом в корпоративном обучении и дополнительном образовании, по моему мнению, в качестве основного формата в современных условиях следует использовать всё же асинхронное обучение, как более гибкое, позволяющее учиться в удобное время, в любом месте. Синхронное обучение скорее должно выполнять дополнительные функции по разъяснению трудных моментов, повышению мотивации и вовлечённости в процесс обучения.
Поделиться ссылкой:
Похожее
ЧТО ТАКОЕ АСИНХРОННОЕ ОБУЧЕНИЕ?
Все виды обучения (и онлайн, и оффлайн) можно разделить на две большие группы: синхронное и асинхронное. Деление это основано, как видно из названия, на синхронизации приёма и отправки информации между субъектами и объектами взаимодействия. Если попросту, то синхронное обучение — это когда приём и передача информации происходят практически одновременно. Сюда можно отнести лекцию, вебинар, популярные ныне прямые эфиры в социальных сетях, чаты. То есть инструменты, при помощи которых слушатель (читатель) получает информацию сразу же и имеет возможность задать вопрос или выполнить задание преподавателя.
Асинхронное дистанционное обучение — формат, при котором контакт между студентом и преподавателем задержан во времени. Участники не пересекаются в физическом пространстве и не «видят» друг друга в виртуальном. При этом курс выполняет свои функции: студенты получают знания, обратную связь (от системы по итогам тестов или преподавателя по факту проверки самостоятельных работ студентов) и движутся по определенной образовательной траектории. Все за счет заранее подготовленных материалов, продуманной логике курса и системе проверки знаний.
Асинхронное обучение всегда предполагает отсроченность приема информации. Сюда можно отнести чтение учебников, статей, блогов, сайтов, интерактивных презентаций, прохождение электронных курсов, тестов, заданий и упражнений, просмотр записанного видео или прослушивание аудиозаписей.
Принято считать, что при асинхронном формате обучения коммуникация между преподавателем и студентами отсутствует. Это не так: преподаватель и студенты могут общаться по электронной почте или в мессенджере внутри образовательной платформы. В процессе обучения студенты получают не только новые знания, но и обратную связь — от образовательной платформы по итогам тестов или от преподавателя после проверки самостоятельных работ студентов.
ОСНОВНЫЕ ХАРАКТЕРИСТИКИ АСИНХРОННОГО ОБУЧЕНИЯ
Основная характеристика асинхронного обучения заключается в том, что оно более или менее «отвязано» от обычных ограничений. То есть не продиктовано временем, местом или сотрудничеством между учителем и учениками. Эта важнейшая тема независимости существенно меняет процесс обучения.
Если в условиях синхронного обучения учитель идёт изучение определённой темы в режиме реального времени, то в условиях асинхронного обучения ученику, как правило, предоставляются ресурсы для самостоятельной опосредованной работы.
Асинхронное обучение, как правило, является технологически интенсивным и зависит от того, будут ли учащиеся и преподаватели иметь доступ к этим инструментам и насколько они обладают опытом работы с ними.
ПЛЮСЫ АСИНХРОННОГО ОБУЧЕНИЯ
— Широкая география. Асинхронное обучение доступно для слушателей из любой точки мира.
— Гибкость. Слушатели могут самостоятельно выбрать график обучения, встраивая его в свой обычный режим.
— Поточность. Для запуска курса необязательно набирать группу — студенты могут начать и завершить обучение в любое время.
МИНУСЫ АСИНХРОННОГО ОБУЧЕНИЯ
— Высокая требовательность. Слушатели должны сами себя мотивировать, обучение в том числе и соблюдение его сроков, являются самостоятельными
— Техническая зависимость. При асинхронном обучении студенты «привязаны» к ПК и Интернету, а также должны обладать определенными техническими навыками, чтобы эффевтивно использовать предлагаемую платформу обучения
— Изолированность. В случае асинхронного обучения, как правило, студенты лишены возможности общения и взаимодействия друг с другом.
КОГДА ЭФФЕКТИВНО АСИНХРОННОЕ ОБУЧЕНИЕ
Асинхронный формат подходит для изучения как гуманитарных, так и технических дисциплин — и даже танцев и йоги.
Асинхронное обучение особенно эффективно, если необходимо:
— запомнить много теоретического материала — асинхронный формат позволяет легко возвращаться к пройденным урокам;
— подготовиться к аттестации или тестированию;
— создать курс для студентов с разным уровнем подготовки — каждый сможет выбрать свой темп и график обучения;
— провести массовое обучение, поскольку обучаться в асинхронном формате могут одновременно сотни человек.
Источники:
https://webinar.ru/blog/chto-takoe-asinhronnoe-obuchenie/?utm_medium=blog&utm_source=post&utm_campaign=synchronous_150419
Внедрение дистанционного обучения
При внедрении системы электронного обучения остается больше вопросов, чем ответов. Синхронный формат или асинхронный? Жанна Петросян или Максим Шкилев? Опыт или… опыт? Делаем ставки, дамы и господа!
Участники поединка
Жанна: Я работаю в сфере eLearning уже 6 лет. За это время мне посчастливилось побывать и в роли студента, и в роли руководителя образовательных проектов. Я преподаватель, автор и разработчик онлайн-курсов – такой вот человек-оркестр. Именно поэтому я могу рассуждать о синхроне и асинхроне с двух сторон.
На моем счету более 25 курсов в различных форматах. Каждый, в среднем, по 3-5 потоков. Не могу сказать, что асинхронное обучение – это плохо. Но в итоге все сводится к обычной математике. По статистике синхронный онлайн-курс заканчивает 70-90% студентов. В асинхроне ситуация уже не такая радужная: до конца едва ли доживает 50% слушателей.
Почему такая разница?
- Проверка домашних заданий
- Обратная связь от преподавателя
- Сопровождение фасилитатора, тьютора или любого другого мотиватора-пинателя
- Командная работа
- Наличие дедлайна
И это все в режиме реального времени! По-моему выбор очевиден.
Максим: Я в “удалённом” обучении с 2006 года. В кавычках, потому что начиналось все с дисков с видеоуроками, которые отправлялись в разные города по почте. Это и был мой первый eLearning.
Асинхронные курсы до сих пор пользуются спросом у крупных корпоративных университетов. Взять, к примеру, внедрение системы электронного обучения в медицинском центре, банке или агрохолдинге. Мы создаем контент, с помощью которого персонал получает знания, навыки и умения по конкретной теме. То есть сотрудники прокачивают свои скиллы по требованию.
Поэтому для меня асинхрон – это когда учебный курс упакован таким образом, что человек может подключиться или вернуться к обучению в любое удобное время. При этом не отменяется роль куратора, который предоставляет обратную связь по домашним заданиям и сопровождает слушателей “до победного”.
Студенты могут обучаться параллельно, но находиться при этом на разных уроках. То есть нет единой группы, которая одновременно переходит от одного элемента курса к другому.
В синхроне все в точности да наоборот. Группа студентов движется по всем этапам обучения одновременно: кто-то выпадает, кто-то догоняет, но эта логика привязана к определенным моментам времени. Мы все участвуем в вебинаре в понедельник в 18:00. Да, вы потом пересмотрите его в записи хоть 10 раз, но задать вопрос спикеру здесь и сейчас можно только в прямом эфире. И не важно, где именно вы при этом находитесь.
Приблизительно так я вижу разницу между этими двумя форматами. Для меня как раз куратор и обратная связь в асинхроне – это обязательный элемент!
Разработка
Жанна: Онлайн-курсы уже давно перестали быть просто хранилищем информации, которая разложена по полочкам в хронологическом порядке. Внедрение электронного обучения – это процесс.
В рамках синхронного курса легче реализовать 3 критерия, которые говорят о том, что перед нами качественный образовательный продукт: взаимодействие слушателя с учебным контентом, преподавателем и другими участниками группы.
Студенты могут работать на виртуальных досках, в индивидуальных кабинетах или зонах взаимного оценивания. Такие курсы эффективны, потому что дают возможность организовать любые виды проектных и командных заданий. Именно они помогают слушателям выйти на тот уровень анализа, который недоступен асинхрону.
Потом, не стоит забывать об адаптивном обучении и выстраивании индивидуальной учебной траектории. Только подумайте, каким высоким должен быть уровень подготовки разработчика/педдизайнера для того, чтобы создать такой курс асинхронно!
Кто приходит к нам обучаться? Как правило, регистрация происходит автоматически и мы не можем этого знать. Еще на этапе разработки нужно вложить очень много времени и сил, чтобы на выходе получился максимально адаптивный курс. Здесь без педдизайнера и методиста просто не обойтись, а значит и стоимость всего процесса возрастает в разы.
Даже если мы говорим об адаптивных тестах, представляете, сколько траекторий нужно прописать заранее? Синхронное обучение более гибкое. Мы можем менять программу и буквально выкраивать курс под нашу аудиторию.
Максим: Такой подход имеет и ряд существенных минусов. Многие разработчики говорят: “Мы запускаем синхронные курсы по принципу “начнем, а там как карта ляжет”. Проведем первый урок, посмотрим на реакцию людей и потом уже сделаем следующий шаг”.
В асинхроне ты проектируешь весь курс. И, действительно, мгновенной обратной связи нет. Ты не знаешь, куда может завести обучение каждого конкретного человека. Но отслеживая реакцию участников, можно переделать контент, поменять домашнее задание или изменить последовательность сообщений для всех дальнейших студентов.
И это касается не только асинхрона.
По поводу контентной составляющей. Возьмем, к примеру, микрообучение – мощнейший тренд. Если у тебя оффлайн-группа, то довольно сложно давать информацию частями. В онлайне студент может просмотреть или прослушать учебные материалы за 5, 10, 15 минут и сразу выполнить задание. Обучение построено так, что он постоянно остается в движении.
Студент как будто находится в компьютерной игре. Прошло 3 часа, у него появилась новая жизнь и он может потратить ее на следующий шаг. И это огромное преимущество онлайна! Кроме того, у авторов асинхронных курсов есть возможность отслеживать и корректировать динамику, начиная с первого-второго человека.
Вместе с тем вы можете показывать опыт предыдущих участников. Студент сдает домашнее задание и сразу же смотрит, как его выполнили до него. В синхронной группе каждый обучается со своей скоростью, поэтому теряется много времени на “давайте подождем, когда все закончат”.
Еще один плюс – ритмика. А именно частота касаний, когда ты предоставляешь человеку ту или иную информацию. У меня есть интенсивы, где обучение проходит в режиме 24/7. Например, онлайн-курс по созданию видеолендинга.
Слушатель собирается утром на работу и получает маленькое задание. Нужно сделать несколько кадров на мобильный телефон для одного из блоков посадочной страницы. Внезапно поход на работу для него превращается из скучной рутины в увлекательный, а главное обучающий квест. Вечером участника ждет уже новая “миссия” – смонтировать отснятый материал. И вуаля! Через 7 дней он показывает друзьям и знакомым готовый ролик с собой в главной роли.
В то же время нам доступна и система ограничений. Выполни задание за 2 дня и получи какую-то плюшку. И это тебе, персонально. Вот такие вот плюсы асинхронного обучения с точки зрения разработки.
Жанна: Какие-то курсы нового поколения получаются. Все-таки они, на мой взгляд, больше смешанные, чем асинхронные. У меня на подобном электронном курсе отучилось 2500 студентов за 2 года. Как проследить учебную аналитику в асинхроне? Каким образом я могу что-то выстроить? Они все настолько разные и я не получаю о них абсолютно никакой информации.
То, о чем вы говорите, здорово. Но повторюсь, что подобный механизм внедрения системы электронного обучения как в ВУЗе, так и в любой коммерческой организации, требует очень высоких компетенций. И, конечно же, времени.
Максим: У каждой уважающей себя системы дистанционного обучения есть такая волшебная штука, как статистика. Она позволяет отследить действия любого студента в конкретный момент времени. И количество здесь роли уже не играет. Все слушатели проходят курс со своей скоростью, но ты можешь отследить в разрезе по заданию/уроку/модулю, кто как себя вел. Так что не вижу никаких проблем.
Команда
Жанна: Синхронное обучение – это, прежде всего, общение с преподавателем. Он занимается проверкой домашних заданий, дает студентам обратную связь, организовывает удаленное командное взаимодействие. Но ему не обязательно брать на себя всю эту работу.
На мой взгляд, гораздо сложнее вести синхронный, чем асинхронный курс. Это связано с тем, что последние берут своей массовостью и меньшей вовлеченность в процесс. Синхронный вариант более трудозатратный, но, в то же время, и более эффективный, потому что именно преподаватель вовлекает студентов в учебный процесс.
Никакой интерактив не заменит личностный контакт. Могу с уверенностью сказать, что хороший тьютор заряжает всю группу на результат.
Какая степень ответственности нужна слушателю и как разработчик должен выявить внутреннюю мотивацию каждого студента на начальном этапе, чтобы курс вовлек пройти его до конца? Это не просто.
Максим: Сила асинхрона в том, что он позволяет уменьшить нагрузку на преподавателя в разы. Чтобы упаковать контент, у нас есть методист, видеомейкер, дизайнер.
Также не будем забывать об ответственности, которую накладывает синхронный формат на носителя знаний. Если ты облажался, то сразу на всю группу. Если у тебя вебинар не пошел, потому что интернет просел, то это для всех. Если что-то случилось или не случилось – все за тобой.
В асинхроне подобные “бока” отслеживаются и исправляются моментально. И остальные 100, 200, 500 человек уже восторгаются, как прекрасно у тебя все сделано. То есть мы можем на ходу перестраивать и оптимизировать курс.
Более того, в процессе обучения 80% вопросов студентов повторяются. Тут и появляется куратор, который отвечает на них от имени самого спикера, особенно если это типовые ситуации. В итоге только 20% вопросов остаются преподавателю.
И еще. В асинхроне нет привязки ко времени. Эксперт может записать видеоурок тогда, когда ему будет удобно, а читать сообщения участников в четко установленные часы. Допустим, в учебном плане прописано, что он будет отвечать на вопросы студентов в рабочие дни с 11:00 до 13:00. И вам, как преподавателю, не нужно бросать свои дела при звуке входящего сообщения.
Жанна: Вы говорите о выгоде для спикера, а я – об эффективности учебного процесса. Работать удаленно вполне реально и в синхронном формате, почему нет? И если технические моменты можно делегировать, то доверять куратору ответы на вопросы по моему курсу я бы не стала. Мне кажется, что все-таки это зона ответственности преподавателя.
Что касается создания видео, то асинхронные курсы должны быть очень высокого качества. Какие-то погрешности связи во время вебинара можно простить. Но плохое качество видео в асинхронном обучении просто недопустимо. Такой продукт требует определенных навыков и компетенций, возможно даже создания собственной студии, а это удовольствие не из дешевых.
Продвижение
Жанна: И в синхронном формате, и в асинхронном команда, которая работает над продвижением, плюс-минус та же. Только в первом случае рекламная кампания стартует за 1-1,5 месяца до запуска курса. Набирается группа и начинается обучение. В асинхроне же люди приходят и уходят на постоянной основе.
Легкий вход допускает до курса много людей, которым он, по сути, и не нужен. А мы тратим время на учебную аналитику и искренне не понимаем, почему студенты массово бросают занятия уже через месяц. В синхронном обучении аудитория более мотивированная. Слушатели приходят, чтобы закрыть определенную потребность. И сбор статистики не впустую, в отличие от асинхрона, где подавляющее большинство студентов не доходит до конца.
Максим: По поводу легкого входа. Воронка продаж и логика того, что человек получает, прикасаясь шаг за шагом к информации о курсе, и в синхроне, и в асинхроне совершенно идентичны. И если она действительно построена на болях целевой аудитории, то вопросов с мотивацией у нас не возникает.
Я соглашусь с тем, что в синхронном обучении за счет группового взаимодействия ощущается сопричастность к процессу. На нем “прокачиваются” даже те, кто по ошибке маркетолога и продажника затянулись в эту группу и не понимают, зачем им это надо.
Сидит слушатель, скучает, а все потому, что не видит, как обучение может повлиять на его жизнь. И тут кто-то говорит: “Боже, когда я об этом узнал, у меня мировоззрение перевернулось!”. И человек думает: “Да, действительно, ничего себе!”. А в курсе этого вообще нет, и преподаватель такого не говорил. Это групповое взаимодействие. Чтобы достичь подобного эффекта в асинхроне, мы добавляем отзывы об уроке от предыдущих студентов.
Возвращаясь к команде, которая занимается продвижением. Одним из самых мощных преимуществ асинхронного обучения остается возможность включаться в процесс тогда, когда у вас есть потребность в этой информации или умениях. А для синхрона действительно нужно 1,5-2 месяца проводить рекламную кампанию, тратить деньги, рисковать попасть в несезон, конкурировать с какими-то классными конференциями и прочими мероприятиями. Много денег уходит в песок, потому что чего-то не предусмотрели.
Предварительный анализ не спасет, так как видеть будущее нам не дано. А команда, которая создает воронку продаж для асинхронного курса, делает точку контакта – лендинг, чат-бот и прочие формы продажи. Она четко фиксированная, потому что отрабатывается на тысячах людей и обеспечивает постоянный приток свежих лидов.
Контент-стратегия подразумевает, что у нас есть какое-то время, чтобы познакомить аудиторию со спикером и плавно подвести к обучению. При этом мы используем именно тот момент, когда человеку “горит и болит”. Это ключевое преимущество продвижения и продаж асинхронного продукта.
Жанна: По поводу того, что курс может совпадать с какими-то важными мероприятиями. Я считаю, что это вообще не проблема, так как задача маркетологов заранее просчитывать подобные ситуации. Все же мне кажется, что вы говорите о несколько утопичной работе команды. Невозможно организовать эффективное взаимодействие между постоянно приходящими и уходящими людьми.
Обучение в асинхроне вялотекущее и вразвалочку. Нет мотивации, нет дедлайнов. Контроль должен быть, все-таки не такие уж мы и ответственные. Признаюсь, что я редко прохожу такие курсы до конца. Даже если понимаю, что они мне нужны. Но постоянно какие-то обстоятельства, что-то отвлекает, мешает.
А когда я вижу, что группа моих однокурсников делает невероятные успехи на доске совместной работы, то меня это ой как подстегивает. То есть здесь уже здоровая конкуренция просыпается. Проходите ли вы чужие асинхронные курсы до конца?
Максим: Лично у меня есть четкий план обучения на следующий год. Все курсы асинхронные. И ключевое, что я буду проходить их тогда, когда мне удобно. То есть у меня есть доступ к материалам. Я могу ехать на встречу и обучаться. И это прекрасно! Благодаря курсам я решаю конкретные проблемы и задачи. При этом мне не нужно ждать какую-то там группу.
Жанна: У меня онлайн-школа английского языка и учебный центр для тех, кто хочет создавать собственные курсы. И в том, и в другом случае знаете, что слушателям нужно в первую очередь? Они приходят и говорят: “Заставьте меня учиться! Мне это нужно, но времени катастрофически не хватает. У меня дети, работа, собака…”.
Мы создаем графики и отмечаем в календарях дни, когда что-то сделали или не сделали для развития своего проекта. Люди сами просят меня вводить в учебный процесс журналы эффективности и доски достижений. В асинхроне самоорганизоваться в разы сложнее.
Методическое сопровождение
Жанна: Если мы говорим о взрослых, то моя задача на начальном этапе – сформировать интерес к материалу. Я должна максимально перенести контент на их профессиональную деятельность. Мы изучаем анкеты, которые получаем во время обучения, и выстраиваем курс дальше на основе домашних заданий и кейсов студентов. В асинхроне я бы опиралась на опыт посторонних людей, которые учились когда-то, а не сейчас.
Максим: Да, это хорошо, когда группа из 5-10 человек, а если из 200? Нагрузка на одного человека просто нереальная! Упаковка курса методистом, дизайнером, видеомейкером снижают давление на преподавателя. Я считаю, что не нужно тратить драгоценное время эксперта на рутинные моменты.
Представьте, что идет синхронное обучение в группе из 200 человек. Студент платит за обратную связь, но он ее не получает, потому что спикер просто не успевает ответить каждому. И это вызывает еще больший негатив.
Такие моменты тоже необходимо учитывать. Вы же не будете выделять любимчиков как в школе, правда? В асинхроне каждый гарантированно получает обратную связь от преподавателя, если он купил соответствующий пакет. И эксперт, при этом, не залипает в компьютер 12 часов в сутки.
Механики работы со студентом
Жанна: Синхронное обучение позволяет группе перейти к более высокоуровневым заданиям. Это возможно и в асинхроне, если у вас учится большое количество людей на постоянной основе. Но как организовать, к примеру, проектную работу между отдельными слушателями?
Максим: Вы правы насчет дополнительной энергии. В асинхронном формате есть поток от преподавателя, но нет потока от участников группы. Как исправить ситуацию?
Во-первых, не забываем о ритмике. То есть утром мы даем мотивирующие материалы, а в пиковое учебное время – практические задания. Их можно отправлять кусочками в течение дня, чтобы обеспечить хорошую динамику. Это огромный плюс! Не нужно куда-то подключаться и бежать галопом за толпой. Ты потребляешь контент тогда, когда тебе максимально удобно.
Кроме того, рано или поздно обучение заканчивается. Приходит время практики, когда бывший студент сталкивается с реальными задачами. И тут уже появляется что? Правильно, необходимость в консультации! А это дополнительные продажи.
При чем мы сейчас говорим не о потоке бессвязных запросов, от которых не знаешь, куда деваться. Человек добрался до определенной точки и готов к квалифицированной помощи.
Технический инструментарий
Жанна: Интерактивное видео, адаптивные тесты, диалоговые тренажеры… Для того, чтобы создать такую четкую и налаженную систему, нужны дорогие инструменты. Вы целый сценарий разрабатываете с разными вариантами развития событий. А это значит, что в СДО должны быть и аналитика, и обратная связь, и рассылки.
В синхронном формате мы также проводим большую работу на образовательных платформах, но требования не такие жесткие. Все же этим процессом можно управлять, поэтому в дорогой системе дистанционного обучения нет такой необходимости.
Максим: Не соглашусь, потому что базовый набор инструментов бесплатный. Мы используем YouTube, Facebook, Telegram или Viber в роли носителя контента. А для ритмики и автоматизации процесса нам нужен либо чат-бот, либо e-mail робот. Да, процесс достаточно кропотливый, но это забота уже конкретного человека, который собирает разрозненные материалы в курс.
По поводу внедрения систем дистанционного обучения. Существуют платформенные решения, тот же Udemy, на которых можно выложить проведенный курс под процент от продаж для дополнительной монетизации. Он получается немного сокращенным, потому что обрезается под требования площадки, но вы все равно дарите контенту новую жизнь.
Более того, подобные агрегаторы обычно занимаются и продвижением курса. Вам даже команда для этого не понадобится – они все делают сами. Так что обе стороны в выигрыше.
Сферы, в которых можно использовать форматы
Жанна: По своему опыту могу сказать, что есть такие сферы, где асинхронное обучение просто не работает. Иностранные языки в первую очередь. Отработка речевых навыков в подобном формате практически невозможна. В медицинских центрах какой может быть асинхрон? Разумеется, есть такие области, специфика которых подразумевает контактную работу с преподавателем. И часто даже не в онлайне, а в оффлайне.
Максим: Все зависит от правильно упакованной системы знаний и логики потребления. В итоге весь смысл синхронного формата сводиться к тому, что мы берем человека за шкирку и куда-то его ведем. Асинхронное обучение – это та информация, которая позволяет здесь и сейчас получить конкретный алгоритм и результат.
Как бы ни бились Жанна с Максимом – правы обе стороны. И побеждает в итоге не синхрон или асинхрон, а микс. Все относительно. Программа внедрения дистанционного обучения зависит прежде всего от целей и результатов, которых вы хотите достичь. Поэтому нужно брать и применять лучшее от каждого формата, чтобы учебный процесс был максимально эффективным.
Жанна Петросян
Специалист по созданию, внедрению и поддержке онлайн-курсов
Максим Шкилев
Предприниматель, консультант, сертифицированный бизнес-тренер
Также рекомендуем:
Асинхронный JavaScript — Изучение веб-разработки
В этом модуле мы рассмотрим asynchronous JavaScript, почему это важно, и как это поможет эффективно справляться с потенциальной блокировкой операций, таких как получение ресурсов с сервера или запись в файл.
- Основные концепции асинхронного программирования
В этой статье мы пройдёмся по нескольким важным концепциям касающихся асинхронного программирования, и того как это выглядит в браузерах и JavaScript. Вы должны усвоить эти концепции прежде чем изучать другие статьи в этом модуле.
- Введение в асинхронный JavaScript
- В этой статье мы кратко расскажем о проблемах связанных с синхронным JavaScript-ом, и взглянем на различные техники асинхронного программирования с которыми вы столкнётесь, покажем вам как эти техники помогают решать проблемы синхронного JavaScript.
- Кооперативная асинхронность в JavaScript: Таймауты и интервалы
- Здесь мы рассматриваем традиционные методы JavaScript, которые позволяют запускать код асинхронно по истечению заданного времени, или с регулярным интервалом (например: заданное количество раз в секунду), обсудим их пользу, а так же их неотъемлемые проблемы.
- Изящная обработка асинхронных операций с Промисами
- Промисы это достаточно новая функция в языке JavaScript, которая позволяет вам откладывать дальнейшие операции, пока предыдущая не выполнится, или реагировать на её неудачное выполнение. Это очень полезно, для установки нужной последовательности операций для корректной работы. Эта статья показывает как работают промисы, и вы рассмотрите то, как они работают в WebAPIs, и узнаете как писать свои собственные.
- Делаем асинхронное программирование проще с async и await
- Промисы могут быть достаточно сложными для написания и понимания, поэтому современные браузеры ввели функцию
async
и операторawait
— где первый позволяет стандартным функциям неявно асинхронно работать с промисами, а последний может использоваться внутриasync
функций, для ожидания промиса, прежде чем функция продолжит свою работу, что делает работу с промисами проще и улучшает читабельность кода. - Выбор правильного подхода
- В завершение этого модуля, мы рассмотрим технологии и функции, которые мы обсуждали, рассмотрим когда и где их надо использовать. А так же дадим рекомендации и расскажем о распространённых подводных камнях, там где это будет необходимо.
Общие концепции асинхронного программирования — Изучите веб-разработку
В этой статье мы рассмотрим ряд важных концепций, касающихся асинхронного программирования, и того, как это выглядит в веб-браузерах и JavaScript. Вы должны понять эти концепции, прежде чем работать с другими статьями модуля.
Предварительные требования: | Базовая компьютерная грамотность, хорошее понимание основ JavaScript. |
---|---|
Цель: | Чтобы понять основные концепции асинхронного программирования и то, как они проявляются в веб-браузерах и JavaScript. |
Обычно код данной программы выполняется одновременно, и одновременно происходит только одно событие. Если функция полагается на результат другой функции, она должна дождаться завершения и возврата другой функции, и пока это не произойдет, вся программа по существу останавливается с точки зрения пользователя.
Пользователи
Mac, например, иногда воспринимают это как вращающийся курсор цвета радуги (или «пляжный мяч», как его часто называют). Этот курсор — это то, как операционная система говорит: «Текущая программа, которую вы используете, должна была остановиться и дождаться завершения чего-то, и это занимает так много времени, что я беспокоился, что вы задаетесь вопросом, что происходит.«
Это разочаровывающий опыт и не очень хорошее использование вычислительной мощности компьютера — особенно в эпоху, когда компьютеры имеют несколько доступных процессорных ядер. Нет смысла сидеть и ждать чего-то, если вы можете позволить другой задаче работать на другом ядре процессора и сообщить вам, когда она будет выполнена. Тем временем это позволяет вам выполнять другую работу, что является основой асинхронного программирования . Это зависит от среды программирования, которую вы используете (веб-браузеры, в случае веб-разработки), чтобы предоставить вам API-интерфейсы, которые позволят вам выполнять такие задачи асинхронно.
Асинхронные методы очень полезны, особенно в веб-программировании. Когда веб-приложение запускается в браузере и выполняет интенсивный фрагмент кода, не возвращая управление браузеру, браузер может казаться зависшим. Это называется , блокировка ; браузер заблокирован от продолжения обработки пользовательского ввода и выполнения других задач до тех пор, пока веб-приложение не вернет управление процессором.
Давайте рассмотрим несколько примеров, которые показывают, что мы подразумеваем под блокировкой.
В нашем примере simple-sync.html (посмотрите, как он работает в реальном времени) мы добавляем прослушиватель событий щелчка к кнопке, чтобы при нажатии он выполнял трудоемкую операцию (вычисляет 10 миллионов дат, а затем выводит последнюю дату в консоль. ), а затем добавляет абзац в DOM:
const btn = document.querySelector ('кнопка');
btn.addEventListener ('щелчок', () => {
let myDate;
for (let i = 0; i <10000000; i ++) {
пусть дата = новая дата ();
myDate = дата
}
консоль.журнал (myDate);
пусть pElem = document.createElement ('p');
pElem.textContent = 'Это новый абзац.';
document.body.appendChild (pElem);
});
При запуске примера откройте консоль JavaScript и нажмите кнопку - вы заметите, что абзац не появляется до тех пор, пока даты не будут вычислены и сообщение консоли не будет зарегистрировано. Код выполняется в том порядке, в котором он указан в исходном коде, и более поздняя операция не выполняется, пока не завершится выполнение более ранней операции.
Примечание : Предыдущий пример очень нереалистичный. Вы бы никогда не посчитали 10 миллионов дат в реальном веб-приложении! Однако он дает вам основную идею.
В нашем втором примере, simple-sync-ui-blocking.html (см. Его вживую), мы имитируем что-то немного более реалистичное, что вы можете встретить на реальной странице. Мы блокируем взаимодействие с пользователем с помощью рендеринга пользовательского интерфейса. В этом примере у нас есть две кнопки:
- Кнопка «Заполнить холст», при нажатии которой доступный
заполняется 1 миллионом синих кружков.
- Кнопка «Щелкните меня, чтобы получить предупреждение», при нажатии которой отображается предупреждающее сообщение.
function strictOperation () {
for (let i = 0; i <1000000; i ++) {
ctx.fillStyle = 'rgba (0,0,255, 0,2)';
ctx.beginPath ();
ctx.arc (random (0, canvas.width), random (0, canvas.height), 10, degToRad (0), degToRad (360), false);
ctx.fill ()
}
}
fillBtn.addEventListener ('щелчок', дорогая операция);
alertBtn.addEventListener ('щелкнуть', () =>
alert ('Ты меня щелкнул!')
);
Если вы нажмете первую кнопку, а затем быстро нажмете вторую, вы увидите, что предупреждение не появляется до тех пор, пока не завершится отображение кругов.Первая операция блокирует вторую, пока она не завершится.
Примечание : Хорошо, в нашем случае это некрасиво, и мы имитируем эффект блокировки, но это распространенная проблема, с которой разработчики реальных приложений постоянно борются, чтобы смягчить ее.
Почему это? Ответ в том, что JavaScript, вообще говоря, однопоточный . На этом этапе нам нужно представить концепцию потоков .
Поток - это, по сути, отдельный процесс, который программа может использовать для выполнения задач.Каждый поток может одновременно выполнять только одну задачу:
Задача A -> Задача B -> Задача C
Каждая задача будет запускаться последовательно; задача должна быть завершена, прежде чем можно будет запустить следующую.
Как мы уже говорили ранее, многие компьютеры теперь имеют несколько ядер, поэтому могут выполнять несколько задач одновременно. Языки программирования, которые могут поддерживать несколько потоков, могут использовать несколько ядер для одновременного выполнения нескольких задач:
Поток 1: Задача A -> Задача B Поток 2: Задача C -> Задача D
JavaScript является однопоточным
JavaScript традиционно является однопоточным.Даже с несколькими ядрами вы могли заставить его запускать задачи только в одном потоке, который называется основным потоком . Наш пример, приведенный выше, выполняется так:
Основная ветка: Отображение кругов на холсте -> Отображение предупреждения ()
Через некоторое время в JavaScript появилось несколько инструментов для решения таких проблем. Веб-воркеры позволяют вам отправлять часть обработки JavaScript в отдельный поток, называемый воркером, чтобы вы могли запускать несколько фрагментов JavaScript одновременно. Обычно вы используете воркер для запуска дорогостоящих процессов из основного потока, чтобы взаимодействие с пользователем не блокировалось.
Основной поток: Задача A -> Задача C Рабочий поток: дорогостоящая задача B
Имея это в виду, взгляните на simple-sync-worker.html (посмотрите, как он работает в реальном времени), снова с открытой консолью JavaScript вашего браузера. Это переработка нашего предыдущего примера, который вычисляет 10 миллионов дат в отдельном рабочем потоке. Теперь, когда вы нажимаете кнопку, браузер может отображать абзац до того, как завершится расчет дат. Первая операция больше не блокирует вторую.
Веб-воркеры довольно полезны, но у них есть свои ограничения. Основная из них заключается в том, что они не могут получить доступ к DOM - вы не можете заставить рабочего делать что-либо напрямую для обновления пользовательского интерфейса. Мы не могли отрендерить 1 миллион синих кругов внутри рабочего; в основном он может просто обрабатывать числа.
Вторая проблема заключается в том, что, хотя код, выполняемый в worker'е, не блокируется, он по-прежнему в основном синхронный. Это становится проблемой, когда функция полагается на результаты нескольких предыдущих процессов.Рассмотрим следующие схемы резьбы:
Основной поток: Задача A -> Задача B
В этом случае предположим, что задача A выполняет что-то вроде выборки изображения с сервера, а задача B затем делает что-то с изображением, например, применяет к нему фильтр. Если вы запустите задачу A, а затем сразу попытаетесь запустить задачу B, вы получите сообщение об ошибке, потому что изображение еще не будет доступно.
Основной поток: Задача A -> Задача B -> | Задача D | Рабочий поток: Задача C -----------> | |
В этом случае предположим, что задача D использует результаты как задачи B, так и задачи C.Если мы можем гарантировать, что оба этих результата будут доступны одновременно, тогда все будет в порядке, но это маловероятно. Если задача D попытается запустить, когда один из ее входов еще недоступен, она выдаст ошибку.
Чтобы исправить такие проблемы, браузеры позволяют нам выполнять определенные операции асинхронно. Такие функции, как Promises, позволяют настроить выполнение операции (например, получение изображения с сервера), а затем дождаться возврата результата перед запуском другой операции:
Основной поток: Задача A Задача B Обещание: | __async operation__ |
Поскольку операция выполняется где-то еще, основной поток не блокируется во время обработки асинхронной операции.
Мы начнем смотреть, как мы можем писать асинхронный код, в следующей статье. Интересный материал, а? Продолжай читать!
Современный дизайн программного обеспечения все больше вращается вокруг использования асинхронного программирования, позволяющего программам выполнять несколько задач одновременно. По мере использования новых и более мощных API-интерфейсов вы обнаружите больше случаев, когда единственный способ делать что-то - асинхронный. Раньше было сложно писать асинхронный код. К этому еще нужно привыкнуть, но стало намного проще.В оставшейся части этого модуля мы подробнее рассмотрим, почему асинхронный код имеет значение и как разработать код, который позволяет избежать некоторых из проблем, описанных выше.
Асинхронное программирование | F # для удовольствия и прибыли
В этом посте мы рассмотрим несколько способов написания асинхронного кода на F #, а также очень краткий пример параллелизма.
Традиционное асинхронное программирование
Как отмечалось в предыдущем посте, F # может напрямую использовать все обычное.NET, такие как Thread
AutoResetEvent
, BackgroundWorker
и IAsyncResult
.
Давайте посмотрим на простой пример, в котором мы ждем срабатывания таймера:
открытая система
пусть userTimerWithCallback =
// создаем событие для ожидания
let event = new System.Threading.AutoResetEvent (false)
// создаем таймер и добавляем обработчик события, который будет сигнализировать о событии
пусть таймер = новый System.Timers.Timer (2000.0)
таймер.Elapsed.Add (весело _ -> event.Set () |> игнорировать)
//Начните
printfn "Ожидание таймера% O" DateTime.Now.TimeOfDay
timer.Start ()
// продолжать работать
printfn "Делаем что-то полезное в ожидании события"
// блокируем таймер через AutoResetEvent
event.WaitOne () |> игнорировать
//сделано
printfn "Таймер установлен на% O" DateTime.Now.TimeOfDay
Здесь показано использование AutoResetEvent
в качестве механизма синхронизации.
- Лямбда регистрируется таймером
.Прошло событие
, и когда событие запускается, AutoResetEvent сигнализируется. - Основной поток запускает таймер, делает что-то еще во время ожидания, а затем блокируется, пока не сработает событие.
- Наконец, примерно через 2 секунды основной поток продолжается.
Приведенный выше код достаточно прост, но требует, чтобы вы создали экземпляр AutoResetEvent,
и может быть ошибочным, если лямбда определена неправильно.
Представляем асинхронные рабочие процессы
F # имеет встроенную конструкцию, называемую «асинхронные рабочие процессы», которая значительно упрощает написание асинхронного кода.Эти рабочие процессы представляют собой объекты, которые инкапсулируют фоновую задачу и предоставляют ряд полезных операций для управления ими.
Вот предыдущий пример, переписанный для использования:
открытая система
// открыть Microsoft.FSharp.Control // Async. * находится в этом модуле.
пусть userTimerWithAsync =
// создаем таймер и связанное с ним асинхронное событие
пусть таймер = новый System.Timers.Timer (2000.0)
let timerEvent = Async.AwaitEvent (timer.Elapsed) |> Async.Ignore
// Начните
printfn "Ожидание таймера% O" DateTime.Now.TimeOfDay
timer.Start ()
// продолжать работать
printfn "Делаем что-то полезное в ожидании события"
// теперь блокируем событие таймера, ожидая завершения асинхронного выполнения
Async.RunSynchronously timerEvent
// сделано
printfn "Таймер установлен на% O" DateTime.Now.TimeOfDay
Вот изменения:
-
AutoResetEvent
и лямбда исчезли и заменены наlet timerEvent = Control.Async.AwaitEvent (timer.Elapsed)
, который создает объектasync
непосредственно из события, без использования лямбда.ignore
добавлен для игнорирования результата. - событие
.WaitOne ()
заменено наAsync.RunSynchronously timerEvent
, которое блокирует асинхронный объект до его завершения.
Вот и все. И проще, и понятнее.
Асинхронные рабочие процессы также можно использовать с IAsyncResult
, парами начало / конец и другими стандартными методами .NET.
Например, вот как можно выполнить асинхронную запись в файл, обернув IAsyncResult
, сгенерированный из BeginWrite
.
пусть fileWriteWithAsync =
// создаем поток для записи в
используйте stream = new System.IO.FileStream ("test.txt", System.IO.FileMode.Create)
// Начните
printfn "Запуск асинхронной записи"
пусть asyncResult = stream.BeginWrite (Array.empty, 0,0, null, null)
// создаем асинхронную оболочку вокруг IAsyncResult
let async = Async.AwaitIAsyncResult (asyncResult) |> Async.Ignore
// продолжать работать
printfn "Делать что-то полезное в ожидании завершения записи"
// теперь блокируем таймер, ожидая завершения асинхронного выполнения
Асинхронный.Выполнить синхронно асинхронно
// сделано
printfn «Асинхронная запись завершена»
Создание и вложение асинхронных рабочих процессов
Асинхронные рабочие процессы также можно создавать вручную.
Новый рабочий процесс создается с использованием ключевого слова async
и фигурных скобок.
Фигурные скобки содержат набор выражений, которые должны выполняться в фоновом режиме.
Этот простой рабочий процесс просто спит на 2 секунды.
let sleepWorkflow = async {
printfn "Запуск рабочего процесса в спящий режим в% O" DateTime.Now.TimeOfDay
делать! Асинхронный сон 2000
printfn "Завершение рабочего процесса в режиме сна в% O" DateTime.Now.TimeOfDay
}
Async.RunSynchronously sleepWorkflow
Примечание: код делать! Async.Sleep 2000
похож на Thread.Sleep
, но предназначен для работы с асинхронными рабочими процессами.
Рабочие процессы могут содержать других асинхронных рабочих процессов, вложенных в них.
В фигурных скобках вложенные рабочие процессы можно заблокировать с помощью команды let! Синтаксис
.
let nestedWorkflow = async {
printfn "Начальный родитель"
позволять! childWorkflow = Async.StartChild sleepWorkflow
// даем ребенку шанс и продолжаем работать
делать! Асинхронный сон 100
printfn "Делать что-то полезное в ожидании"
// блокируем ребенка
позволять! результат = childWorkflow
// сделано
printfn "Законченный родитель"
}
// запускаем весь рабочий процесс
Async.RunSynchronously nestedWorkflow
В асинхронных рабочих процессах очень удобно то, что они поддерживают встроенный механизм отмены.Никакого специального кода не требуется.
Рассмотрим простую задачу, которая печатает числа от 1 до 100:
let testLoop = async {
для i в [1..100] do
// сделай что-нибудь
printf "% i до .." i
// поспать немного
делать! Асинхронный сон 10
printfn "..after"
}
Можем протестировать обычным способом:
Async.RunSynchronously testLoop
Теперь предположим, что мы хотим отменить эту задачу на полпути. Как лучше всего это сделать?
В C # нам пришлось бы создавать флаги для передачи, а затем часто их проверять, но в F # этот метод встроен с использованием класса CancellationToken
.
Вот пример того, как мы можем отменить задачу:
открытая система
открыть System.Threading
// создаем источник отмены
используйте cancellationSource = new CancellationTokenSource ()
// запускаем задачу, но на этот раз передаем токен отмены
Async.Start (testLoop, cancellationSource.Token)
// Подожди немного
Нить. Сон (200)
// отмена через 200 мс
cancellationSource.Cancel ()
В F # любой вложенный асинхронный вызов автоматически проверяет токен отмены!
В данном случае это была строка:
Как видно из выходных данных, в этой строке произошла отмена.
Последовательное и параллельное создание рабочих процессов
Еще одна полезная особенность асинхронных рабочих процессов заключается в том, что их можно легко комбинировать различными способами: как последовательно, так и параллельно.
Давайте снова создадим простой рабочий процесс, который просто спит определенное время:
// создаем рабочий процесс для сна на время
let sleepWorkflowMs ms = async {
printfn «% i ms рабочий процесс запущен» ms
делать! Async.Sleep мс
printfn «% i ms рабочий процесс завершен» ms
}
Вот версия, в которой последовательно сочетаются два из них:
let workflowInSeries = async {
позволять! sleep1 = sleepWorkflowMs 1000
printfn "Готово"
позволять! sleep2 = sleepWorkflowMs 2000
printfn "Готово два"
}
#время
Асинхронный.RunSynchronously workflowInSeries
#время
А вот версия, которая объединяет два из них параллельно:
// Создайте их
пусть sleep1 = sleepWorkflowMs 1000
пусть sleep2 = sleepWorkflowMs 2000
// запускаем их параллельно
#время
[sleep1; sleep2]
|> Асинхронный параллельный
|> Async.RunSynchronously
#время
Примечание. Команда
#time
включает и выключает таймер. Он работает только в интерактивном окне, поэтому для правильной работы этот пример необходимо отправить в интерактивное окно.
Мы используем опцию #time
, чтобы показать общее прошедшее время, которое, поскольку они выполняются параллельно, составляет 2 секунды. Если бы они запускались последовательно, это заняло бы 3 секунды.
Также вы можете увидеть, что вывод иногда искажается, потому что обе задачи записываются в консоль одновременно!
Этот последний пример является классическим примером подхода «вилка / соединение», когда порождается несколько дочерних задач, а затем родитель ждет их.
все доделать.Как видите, с F # это очень просто!
Пример: асинхронный веб-загрузчик
В этом более реалистичном примере мы увидим, насколько легко преобразовать существующий код из неасинхронного стиля в асинхронный,
и соответствующее увеличение производительности, которое может быть достигнуто.
Итак, вот простой загрузчик URL, очень похожий на тот, который мы видели в начале серии:
открыть System.Net
открытая система
открытая система.IO
пусть fetchUrl url =
let req = WebRequest.Create (Uri (url))
используйте resp = req.GetResponse ()
используйте stream = resp.GetResponseStream ()
используйте reader = new IO.StreamReader (stream)
пусть html = reader.ReadToEnd ()
printfn "завершил загрузку% s" url
А вот код, чтобы рассчитать время:
// список сайтов для выборки
let sites = ["http://www.bing.com";
"http://www.google.com";
«http://www.microsoft.com»;
"http: // www.amazon.com ";
"http://www.yahoo.com"]
#time // включаем интерактивный таймер
sites // начинаем со списка сайтов
|> List.map fetchUrl // перебираем каждый сайт и загружаем
#time // выключить таймер
Запишите потраченное время, и давайте посмотрим, сможем ли мы его улучшить!
Очевидно, что приведенный выше пример неэффективен - одновременно посещается только один веб-сайт. Программа была бы быстрее, если бы мы могли посещать их все одновременно.
Так как же преобразовать это в параллельный алгоритм? Логика будет примерно такой:
- Создайте задачу для каждой загружаемой веб-страницы, а затем для каждой задачи логика загрузки будет примерно такой:
- Начните загрузку страницы с веб-сайта. Пока это происходит, сделайте паузу и позвольте другим задачам по очереди.
- Когда загрузка будет завершена, выйдите из спящего режима и продолжите выполнение задачи
- Наконец, запустите все задачи и позвольте им приступить к делу!
К сожалению, это довольно сложно сделать на стандартном C-подобном языке.В C #, например, вам нужно создать обратный вызов для завершения асинхронной задачи. Управление этими обратными вызовами болезненно и создает много дополнительного кода поддержки, который мешает пониманию логики. Для этого есть несколько элегантных решений, но в целом соотношение сигнал / шум для параллельного программирования на C # очень высокое *.
* На момент написания статьи. В будущих версиях C # будет ключевое слово await
, которое похоже на то, что есть в F # сейчас.
Но, как вы можете догадаться, F # упрощает эту задачу. Вот параллельная версия кода загрузчика на F #:
открыть Microsoft.FSharp.Control.CommonExtensions
// добавляет AsyncGetResponse
// Асинхронное получение содержимого веб-страницы
пусть fetchUrlAsync url =
async {
let req = WebRequest.Create (Uri (url))
использовать! resp = req.AsyncGetResponse () // новое ключевое слово "use!"
используйте stream = resp.GetResponseStream ()
используйте reader = new IO.StreamReader (поток)
пусть html = reader.ReadToEnd ()
printfn "завершил загрузку% s" url
}
Обратите внимание, что новый код выглядит почти так же, как оригинал. Есть всего несколько мелких изменений.
- Изменение с «
use resp =
» на «use! resp =
»- это именно то изменение, о котором мы говорили выше - пока выполняется асинхронная операция, пусть другие задачи имеют ход. - Мы также использовали метод расширения
AsyncGetResponse
, определенный в пространстве именCommonExtensions
.Это возвращает асинхронный рабочий процесс, который мы можем вложить в основной рабочий процесс. - Кроме того, весь набор шагов содержится в оболочке «
async {...}
», которая превращает его в блок, который можно запускать асинхронно.
А вот синхронизированная загрузка с использованием асинхронной версии.
// список сайтов для выборки
let sites = ["http://www.bing.com";
"http://www.google.com";
«http://www.microsoft.com»;
"http: // www.amazon.com ";
"http://www.yahoo.com"]
#time // включаем интерактивный таймер
места
|> List.map fetchUrlAsync // создаем список асинхронных задач
|> Async.Parallel // настраиваем задачи для параллельного выполнения
|> Async.RunSynchronously // запускаем их
#time // выключить таймер
Как это работает:
-
fetchUrlAsync
применяется к каждому сайту. Загрузка не начинается сразу, а возвращается асинхронный рабочий процесс для последующего запуска. - Чтобы настроить одновременное выполнение всех задач, мы используем функцию
Async.Parallel
- Наконец, мы вызываем
Async.RunSynchronously
, чтобы запустить все задачи, и ждем, пока они все остановятся.
Если вы попробуете этот код самостоятельно, вы увидите, что асинхронная версия намного быстрее, чем синхронизированная. Неплохо для нескольких незначительных изменений кода! Самое главное, что основная логика по-прежнему очень ясна и не загромождена шумом.
Пример: параллельное вычисление
В заключение давайте еще раз быстро рассмотрим параллельное вычисление.
Прежде чем мы начнем, я должен предупредить вас, что приведенный ниже пример кода предназначен только для демонстрации основных принципов.
Тесты из «игрушечных» версий распараллеливания, подобных этой, не имеют смысла, потому что любой реальный параллельный код имеет очень много зависимостей.
И также имейте в виду, что распараллеливание редко бывает лучшим способом ускорить ваш код. Ваше время почти всегда лучше потратить на улучшение ваших алгоритмов.
Я готов поспорить, что моя серийная версия quicksort против вашей параллельной версии bubbleort в любой момент!
(Подробнее о том, как повысить производительность, см. В серии статей по оптимизации)
В любом случае, с этой оговоркой, давайте создадим небольшую задачу, которая потребляет немного ресурсов процессора.Мы будем тестировать это последовательно и параллельно.
пусть childTask () =
// проглотить процессор.
для i в [1..1000] do
для i в [1..1000] do
сделать "Привет" .Contains ("H") |> игнорировать
// нас не волнует ответ!
// Тестируем дочернюю задачу самостоятельно.
// При необходимости скорректируем верхние границы
// чтобы сделать это примерно за 0,2 секунды
#время
childTask ()
#время
Отрегулируйте верхние границы петель по мере необходимости, чтобы выполнить этот прогон примерно за 0,2 секунды.
Теперь давайте объединим их в одну последовательную задачу (используя композицию) и протестируем ее с помощью таймера:
пусть parentTask =
childTask
|> Список.копировать 20
|> List.reduce (>>)
//тест
#время
parentTask ()
#время
Это займет около 4 секунд.
Теперь, чтобы сделать childTask
распараллеливаемым, мы должны заключить его в async
:
let asyncChildTask = async {return childTask ()}
А чтобы объединить кучу асинхронных операций в одну параллельную задачу, мы используем Async.Parallel
.
Давайте проверим это и сравним тайминги:
пусть asyncParentTask =
asyncChildTask
|> Список.копировать 20
|> Асинхронный параллельный
//тест
#время
asyncParentTask
|> Async.RunSynchronously
#время
На двухъядерном компьютере параллельная версия работает примерно на 50% быстрее. Он, конечно, будет расти пропорционально количеству ядер или процессоров, но сублинейно. Четыре ядра будут быстрее одного ядра, но не в четыре раза быстрее.
С другой стороны, как и в примере с асинхронной загрузкой через Интернет, несколько незначительных изменений кода могут иметь большое значение, при этом код остается легким для чтения и понимания.Поэтому в тех случаях, когда параллелизм действительно поможет, хорошо знать, что его легко организовать.
Обучение асинхронной работе требует времени
Работали ли вы в традиционном офисе или работали удаленно, разработка программного обеспечения всегда носила асинхронный характер. Но теперь, когда почти все мы работаем удаленно, важно точно определить, что значит асинхронная работа, и ознакомиться с некоторыми конкретными советами для новичков.
Так что же такое асинхронная работа? При асинхронной работе ваша работа должна быть поставлена в очередь таким образом, чтобы она не останавливалась в ожидании, пока другие предоставят вам результаты или разъяснения.Это требует изменения в вашей работе. Нам часто нравится решать одну задачу за раз, пока она не будет завершена, даже если это означает привлечение других, чтобы немедленно получить необходимую информацию. При асинхронной работе это не вариант, поэтому вам нужно иметь возможность работать над задачей, выяснять, что требуется от других, и асинхронно делиться этим с нужными людьми, а затем переходить к другой задаче, ожидая этой информации.
Ничто из этого не означает, что у нас никогда не должно быть синхронного общения.Видеоконференцсвязь и чат - необходимые инструменты, но их следует использовать с осторожностью. Джейсон Фрид и DHH лучше всего сказали об этом в книге «Не обязательно быть сумасшедшей на работе»: «Иногда в реальном времени, а большую часть времени - асинхронно».
Итак, вот десять советов, которые помогут вам избежать некоторых распространенных ошибок и быстро организовать продуктивный асинхронный рабочий процесс.
Цели, а не деятельность . Многие новые асинхронные рабочие процессы чувствуют необходимость «выглядеть занятыми». Однако асинхронная работа связана с целями, а не с деятельностью.Сосредоточьтесь на задачах, которые вам были поставлены, расслабьтесь и наслаждайтесь преимуществами асинхронной работы. Это сократит ненужную командную болтовню, поможет вам лучше работать и позволит вам наслаждаться новым балансом между работой и личной жизнью.
Соблюдайте установленный график. Когда вы впервые начинаете работать удаленно, установите расписание. Многие компании устанавливают основные часы работы для удаленных сотрудников. Если так, то это хорошее место для начала; составьте свой график в соответствии с этими основными часами. По мере того, как вы привыкните к рутине, вы поймете, что лучше всего подходит для вас.Если вы рано встаете, вы, возможно, захотите провести больше часов рано утром, или если вы любите поспать, вы можете наслаждаться бранчем каждый день и работать до сумерек.
Самодокументирующийся код . Будь то четкое указание на то, как вы пишете код, или написание хороших сообщений о фиксации, существуют всевозможные способы, обеспечивающие хорошую асинхронную связь в течение жизненного цикла разработки программного обеспечения. Жизненный цикл разработки программного обеспечения - это собственное инженерное собрание. Пусть ваш код и инструменты, которые вы используете, говорят сами за себя, так что вам не придется.
Знайте (и используйте) подходящие инструменты . Hangouts и Zoom - это хорошо, но иногда они представляют собой роскошь, которую асинхронные рабочие должны использовать экономно. Скорее, чаще используются такие инструменты, как Slack или Stackoverflow для команд, и инструменты управления проектами, такие как Jira или Asana. Эти инструменты позволяют переносить знания за пределы виртуальных собраний в открытое пространство, в котором другие могут извлечь выгоду в удобное для них время.
Картинка стоит 1000 слов .Изображения, ссылки и другие вспомогательные материалы могут иметь большое значение для сообщения о проблеме или проблеме. Эмодзи и анимированные GIF-файлы не зря популярны! Они позволяют нам делиться нюансами, которые невозможно передать словами. Подобно тому, как смайлики могут выразить ваше настроение, снимки экрана или даже короткое видео о технической проблеме могут дать контекст и понимание проблемы, на объяснение которой у вас уйдет в два раза больше времени.
Учитесь у других в вашей новой организации или поищите в своей местной встрече или технической группе того, кто уже работает асинхронно и удаленно.Скорее всего, в вашем кругу есть кто-то, кто хотел бы, чтобы вы угостили их обедом и поинтересовались асинхронными стратегиями, которые им подходят.
Оптимизируйте ваше общение . Асинхронное общение требует нужного количества информации для нужных людей в нужное время. Внимательно относитесь к общению, но не переусердствуйте. Ваши сообщения должны содержать достаточно информации, чтобы охватить последующие вопросы, а также давать контекст, но не перегружать получателя нерелевантными данными.Разумно относитесь к сообщениям @here и @everyone в групповых чатах, а также к включению или пересылке электронных писем людям, которые могут иметь лишь косвенный интерес к разговору.
Прозрачность - это цель, но осмотрительность имеет значение . Вы много слышите о прозрачности как о принципе асинхронной работы. Прозрачность имеет значение, но не менее важна свобода действий. Я все еще подписываюсь под тем, что называю виртуальным золотым правилом; Если вы не хотите этого делать в реальном офисе, не делайте этого в виртуальном.Если ваш коллега сделает пул-реквест, вы не войдете в комнату отдыха и не ляпнете: «Чувак, этот пул-реквест был мусором!» Точно так же не забывайте о том, чем вы делитесь и как вы обращаетесь к другим в публичных каналах чата. В приведенном выше примере было бы разумнее отправить этому человеку личное сообщение для решения проблемы. Они оценят осмотрительность и не будут стыдиться публичного осуждения их работы.
Отключить в течение дня . Отключитесь, чтобы сосредоточиться и зарядить батареи.В асинхронной среде отвлечение может стать серьезным, поэтому будьте внимательны в управлении уведомлениями. Не бойтесь откладывать или закрывать приложения, чтобы потратить солидный отрезок времени на выполнение одной задачи. Просто не забывайте возвращаться каждые несколько часов, чтобы решать проблемы или отвечать другим, когда это необходимо. Чтобы восстановить свое психическое состояние, физически отключитесь от рабочего места, прогулявшись по кварталу. Позвоните маме или старому другу, чтобы ненадолго отвлечься от работы.
Async не означает асоциальный .Цель асинхронной работы - эффективность, но это не значит, что вы не можете получать удовольствие. Многие компании проводят виртуальные вечеринки или счастливые часы, чтобы сотрудники могли распустить волосы своего аватара и познакомиться со своими товарищами по команде на личном уровне. Тот факт, что большая часть вашей работы выполняется удаленно или асинхронно, не означает, что вам не следует использовать возможности для общения и веселья со своей командой.
Я считаю, что пандемия коронавируса коренным образом изменит мир во многих отношениях. Одним из этих изменений будет то, как мы работаем.Теперь, когда многие из нас вынуждены работать асинхронно, мы заберем этот навык с собой, когда все вернется в норму.
Какие ваши любимые советы по асинхронной работе? Свяжитесь со мной в Твиттере или поделитесь своими комментариями ниже.
Удачного кодирования! 🤓
Теги: бюллетень, удаленная работа, stackoverflow
Понимание асинхронного программирования на Python - dbader.org
Как использовать Python для написания асинхронных программ и почему вы захотите это сделать.
Синхронная программа - это то, что большинство из нас начинало писать, и ее можно рассматривать как выполнение одного шага выполнения за раз, один за другим.
Даже с условным ветвлением, циклами и вызовами функций мы все еще можем думать о коде с точки зрения выполнения одного шага выполнения за раз, а после его завершения переходить к следующему.
Вот несколько примеров программ, которые будут работать таким образом:
Программы пакетной обработки часто создаются как синхронные программы: получают некоторый ввод, обрабатывают его, создают некоторый вывод.Один шаг логически следует за другим, пока мы не создадим желаемый результат. На самом деле программе нет ничего, на что следует обращать внимание, кроме этих шагов, и именно в таком порядке.
Программы командной строки часто представляют собой небольшие быстрые процессы для «преобразования» чего-то во что-то другое. Это можно выразить как серию шагов программы, которые выполняются последовательно и выполняются.
Асинхронная программа ведет себя иначе. Он по-прежнему выполняет один шаг за раз.Однако разница в том, что система может не ждать завершения этапа выполнения, прежде чем двигаться дальше.
Это означает, что мы продолжаем выполнять шаги программы, даже если предыдущий шаг (или несколько шагов) выполняется «где-то еще». Это также означает, что когда один из этих шагов выполнения выполняется «где-то еще», наш программный код каким-то образом должен его обработать.
Зачем нам писать программу таким образом? Ответ прост: это помогает нам справляться с определенными типами проблем программирования.
Вот концептуальная программа, которая может быть кандидатом для асинхронного программирования:
Давайте посмотрим на упрощенный веб-сервер
Его основная единица работы такая же, как мы описали выше для пакетной обработки; получить ввод, обработать его, создать вывод. Написанный как синхронная программа, это создаст рабочий веб-сервер.
Это также был бы абсолютно ужасный веб-сервер .
Почему? В случае веб-сервера одна единица работы (ввод, процесс, вывод) - не единственная его цель.Его реальная цель - обрабатывать сотни, возможно, тысячи единиц работы одновременно и в течение длительных периодов времени.
Можем ли мы улучшить наш синхронный веб-сервер? Конечно, мы можем оптимизировать шаги выполнения, чтобы сделать их как можно быстрее. К сожалению, у этого подхода есть вполне реальные ограничения, которые приводят к тому, что веб-сервер не может отвечать достаточно быстро и не может обрабатывать достаточное количество текущих пользователей.
Каковы реальные пределы оптимизации описанного выше подхода? Скорость сети, скорость ввода-вывода файлов, скорость запросов к базе данных, скорость других подключенных служб и т. Д.Общей чертой этого списка является то, что все они являются функциями ввода-вывода. Все эти элементы на много порядков медленнее, чем скорость обработки нашего процессора.
В синхронной программе , если этап выполнения запускает запрос к базе данных (например), ЦП по существу простаивает в течение длительного времени, прежде чем запрос вернется с некоторыми данными, и он может продолжить следующий этап выполнения.
Для пакетно-ориентированных программ это не приоритет, обработка результатов этого ввода-вывода является целью и часто занимает гораздо больше времени, чем ввод-вывод.Любые усилия по оптимизации будут сосредоточены на обработке, а не на вводе-выводе.
Операции ввода-вывода файлов, сети и базы данных выполняются довольно быстро, но все же намного медленнее, чем ЦП. Методы асинхронного программирования позволяют нашим программам использовать преимущества относительно медленных процессов ввода-вывода и освобождать ЦП для выполнения другой работы.
Когда я начал пытаться понять асинхронное программирование, люди, которых я спрашивал, и документация, которую я читал, много говорили о важности написания неблокирующего кода.Да, мне это тоже ни разу не помогло.
Что такое неблокирующий код? Что такое код блокировки? Эта информация была похожа на справочное руководство без какого-либо практического контекста о том, как использовать эту техническую деталь осмысленным образом.
Реальный мир асинхронен
Асинхронные программы пишутся по-другому, и от них сложно разобраться. И это интересно, потому что мир, в котором мы живем, и то, как мы с ним взаимодействуем, почти полностью асинхронен.
Вот пример, к которому многие из вас могут относиться: быть родителем, пытающимся делать несколько вещей одновременно; балансируйте в чековой книжке, постирайте немного и присматривайте за детьми.
Мы делаем это, даже не задумываясь, но давайте немного разберемся:
Уравновешивание чековой книжки - это задача, которую мы пытаемся выполнить, и мы можем рассматривать ее как синхронную задачу; один шаг следует за другим, пока он не будет выполнен.
Однако мы можем оторваться от нее, чтобы заняться стиркой, разгрузить сушильную машину, переместить одежду из стиральной машины в сушильную и запустить новую загрузку в стиральной машине. Однако эти задачи можно выполнять асинхронно.
Хотя на самом деле мы работаем со стиральной машиной и сушилкой, это синхронная задача, и мы работаем, но основная задача выполняется после того, как мы запускаем стиральную машину и сушилку и уходим, чтобы вернуться к работе над задачей чековой книжки. Теперь задача асинхронная, стиральная машина и сушилка будут работать независимо, пока не сработает зуммер, уведомляющий нас о том, что тот или другой требует внимания.
Наблюдать за детьми - еще одна асинхронная задача. После того, как они настроены и начинают играть, они делают это независимо (как бы) до тех пор, пока им не понадобится внимание; кто-то голоден, кто-то ранен, кто-то тревожно кричит, и мы, как родители, реагируем на это.Дети - это длительная задача с высоким приоритетом, превосходящая любую другую задачу, которую мы выполняем, например чековую книжку или стирку.
Этот пример иллюстрирует как блокирующий, так и неблокирующий код. Например, пока мы перемещаем хвалу, центральный процессор (родительский) занят и не может выполнять другую работу.
Но это нормально, потому что ЦП занят и задача выполняется относительно быстро. Когда мы запускаем стиральную машину и сушилку и возвращаемся, чтобы сделать что-то еще, теперь задача стирки стала асинхронной, потому что ЦП делает что-то еще, изменил контекст, если вы захотите, и будет уведомлен, когда задача стирки будет завершена машиной. зуммеры.
Как люди, мы работаем таким образом, что, естественно, всегда манипулируем несколькими вещами одновременно, часто даже не задумываясь об этом. У программистов уловка состоит в том, как преобразовать такое поведение в код, который делает то же самое.
Давайте попробуем «запрограммировать» это, используя идеи кода, с которыми вы, возможно, знакомы:
Мысленный эксперимент №1: "Группирующий" родитель
Подумайте о том, чтобы попытаться выполнить эти задачи полностью синхронно. Если мы в этом сценарии хорошие родители, мы просто наблюдаем за детьми, ожидая, что произойдет что-то, требующее нашего внимания.Ничего другого, вроде чековой книжки или стирки, в этом сценарии сделать нельзя.
Мы можем изменить приоритеты задач по своему усмотрению, но только одна из них будет выполняться одновременно синхронно, одна за другой. Это было бы похоже на синхронный веб-сервер, описанный выше, он работал бы, но это был бы ужасный образ жизни.
Ничего, кроме наблюдения за детьми, делалось до тех пор, пока они не уснули, все остальные дела выполнялись после этого, до глубокой ночи. Через пару недель большинство родителей выпрыгнет из окна.
Мысленный эксперимент № 2: «Опрос» родитель
Давайте изменим ситуацию так, чтобы с помощью опроса можно было выполнять множество задач. При таком подходе родитель периодически отрывается от любой текущей задачи и проверяет, не требует ли внимания какая-либо из других задач.
Поскольку мы программируем родителя, давайте сделаем интервал между опросами примерно пятнадцатью минутами. Итак, здесь каждые пятнадцать минут родитель ходит, чтобы проверить, нужно ли уделять внимание стиральной машине, сушилке или детям, а затем возвращается к работе с чековой книжкой.Если что-то из этого требует внимания, работа, которую он выполняет, и родитель возвращается к задаче чековой книжки и продолжает цикл опроса.
Работает, задачи выполняются, но есть пара проблем. Центральный процессор (родитель) тратит много времени на проверку того, что не требует внимания, потому что оно не выполнено, например, стиральной машины и сушилки. Учитывая интервал опроса, задачи вполне могут быть завершены, но они не будут привлекать внимания в течение некоторого времени, вплоть до пятнадцати минут.А высокий приоритет наблюдения за детским заданием, вероятно, не выдержал бы возможного окна в пятнадцать минут без внимания, когда что-то могло пойти не так.
Мы могли бы решить эту проблему, сократив интервал опроса, но теперь ЦП тратит еще больше времени на переключение контекста между задачами, и мы начинаем достигать точки убывающей отдачи. И снова пара недель такой жизни и, ну, посмотрите мой предыдущий комментарий об окне и прыжках.
Мысленный эксперимент № 3: Родитель с «нитями»
Родители часто слышат: «Если бы я только мог клонировать себя».Поскольку мы делаем вид, что можем программировать родителей, мы можем сделать это с помощью потоковой передачи.
Если мы думаем обо всех задачах как о одной «программе», мы можем разбить задачи и запустить их как потоки, так сказать, клонируя родительский элемент. Теперь для каждой задачи есть родительский экземпляр; наблюдение за детьми, наблюдение за сушилкой, наблюдение за стиральной машиной и ведение чековой книжки - все работает независимо. Похоже, это неплохое решение программной проблемы.
Но так ли это? Поскольку мы должны явно указывать родительским экземплярам (процессорам), что делать в программе, мы можем столкнуться с некоторыми проблемами, потому что все экземпляры совместно используют все в программном пространстве.
Например, родитель, контролирующий сушилку, видит, что одежда высохла, берет на себя управление сушилкой и начинает разгрузку. Предположим, что пока родитель-сушилка выгружает одежду, родитель-владелец стиральной машины видит, что стиральная машина закончена, берет на себя управление стиральной машиной, а затем хочет взять под управление сушилку, чтобы переместить одежду из стиральной машины в сушильную. Когда родитель-сушилка закончит выгружать одежду, родитель хочет взять под свой контроль стиральную машину и переместить одежду из стиральной машины в сушильную.
Теперь эти два родителя зашли в тупик.
Оба имеют контроль над своим собственным ресурсом и хотят контроля над другим ресурсом. Они будут вечно ждать, пока другой освободит контроль. Как программистам, нам нужно написать код, чтобы разрешить эту ситуацию.
Вот еще одна проблема, которая может возникнуть из родительского потока. Предположим, что, к сожалению, ребенок получает травму, и этот родитель должен взять ребенка под неотложную помощь. Это происходит сразу же, потому что родительский клон посвящен наблюдению за детьми.Но при неотложной медицинской помощи родитель должен выписать довольно крупный чек для покрытия франшизы.
Тем временем родитель, работающий с чековой книжкой, не знает, что выписывается этот большой чек, и внезапно на семейном счете оказывается больше средств. Поскольку родительские клоны работают в рамках одной и той же программы, а семейные деньги (чековая книжка) являются общим ресурсом в этом мире, нам нужно найти способ, чтобы ребенок, наблюдающий за родителем, мог сообщить родителю с чековой книжкой о том, что происходит. Или предоставьте какой-то механизм блокировки, чтобы ресурс мог одновременно использовать только один родитель с обновлениями.
Все эти вещи управляемы в программном коде потоковой передачи, но это сложно сделать правильно, и трудно отладить, когда он ошибается.
Давайте напишем код Python
Теперь мы воспользуемся некоторыми подходами, описанными в этих «мысленных экспериментах», и превратим их в работающие программы на Python.
Вы можете загрузить весь пример кода из этого репозитория GitHub.
Все примеры в этой статье были протестированы с Python 3.6.1, а файл requirements.txt
, включенный в примеры кода, указывает, какие модули вам понадобятся для запуска всех примеров.
Я настоятельно рекомендую настроить виртуальную среду Python для запуска кода, чтобы не мешать работе Python в вашей системе.
Пример 1: Синхронное программирование
В этом первом примере показан несколько надуманный способ заставить задачу «работать» из очереди и выполнять эту работу. В этом случае работа просто получает число, и задача считается до этого числа.Он также распечатывает его на каждом шаге подсчета и выводит итоговый результат в конце. Придуманная часть заключается в том, что эта программа предоставляет простую основу для нескольких задач для обработки работы в очереди.
"" " example_1.py Просто небольшой пример, показывающий синхронное выполнение "задач" "" " очередь импорта def задача (имя, work_queue): если work_queue.empty (): print (f'Task {name} ничего не делать ') еще: пока не work_queue.empty (): count = work_queue.get () всего = 0 для x в диапазоне (количество): print (f'Task {имя} выполняется ') всего + = 1 print (f'Task {name} total: {total} ') def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Очередь() # поставьте "работу" в очередь для работы в [15, 10, 5, 2]: work_queue.put (работа) # создать несколько задач задачи = [ (задача, 'One', work_queue), (задача, 'Два', work_queue) ] # запускаем задачи для t, n, q в задачах: т (п, д) если __name__ == '__main__': главный()
«Задача» в этой программе - это просто функция, которая принимает строку и очередь. При выполнении он проверяет, есть ли что-нибудь в очереди для обработки, и если да, то извлекает значения из очереди, запускает цикл for для подсчета до этого значения и выводит итог в конце.Это продолжается до тех пор, пока в очереди не останется ничего, и завершается.
Когда мы запускаем эту задачу, мы получаем список, показывающий, что эта задача выполняет всю работу. Цикл внутри него потребляет всю работу в очереди и выполняет ее. Когда этот цикл завершается, вторая задача получает шанс выполнить, но обнаруживает, что очередь пуста, поэтому она печатает соответствующий запрос и завершает работу. В коде нет ничего, что позволяло бы первой и второй задаче хорошо играть вместе и переключаться между ними.
Пример 2: Простой совместный параллелизм
Следующая версия программы ( example_2.py
) добавляет способность двух задач хорошо играть вместе за счет использования генераторов. Добавление оператора yield в функцию задачи означает, что цикл завершается в этой точке, но сохраняет свой контекст, чтобы его можно было перезапустить позже. Цикл «выполнить задачи» позже в программе использует это преимущество, когда вызывает t.next ()
. Этот оператор перезапускает задачу с того места, где она была ранее завершена.
Это форма кооперативного параллелизма. Программа передает контроль над своим текущим контекстом, чтобы можно было запустить что-то еще.В этом случае он позволяет нашему примитивному планировщику «запускать задачи» запускать два экземпляра функции задачи, каждый из которых потребляет работу из одной и той же очереди. Это в некотором роде умно, но нужно много работать, чтобы получить те же результаты, что и в первой программе.
"" " example_2.py Просто короткий пример, демонстрирующий простой конечный автомат на Python "" " очередь импорта def задача (имя, очередь): пока не queue.empty (): count = queue.get () всего = 0 для x в диапазоне (количество): print (f'Task {имя} выполняется ') всего + = 1 урожай print (f'Task {name} total: {total} ') def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Очередь() # поставьте "работу" в очередь для работы в [15, 10, 5, 2]: work_queue.put (работа) # создать несколько задач задачи = [ задача ('One', work_queue), задача ('Два', work_queue) ] # запускаем задачи done = Ложь пока не сделано: за t в задачах: пытаться: Следующий т) кроме StopIteration: tasks.remove (t) если len (tasks) == 0: done = True если __name__ == '__main__': главный()
Когда эта программа запущена, выходные данные показывают, что и первая, и вторая задача выполняются, потребляя работу из очереди и обрабатывая ее.Это то, что задумано, обе задачи обрабатывают работу, и каждая в конечном итоге обрабатывает два элемента из очереди. Но опять же, для достижения результата придется немало поработать.
Уловка здесь заключается в использовании оператора yield
, который превращает функцию задачи в генератор для выполнения «переключения контекста». Программа использует этот переключатель контекста для запуска двух экземпляров задачи.
Пример 3: Совместное одновременное использование с блокирующими вызовами
Следующая версия программы ( example_3.py
) точно такой же, как и предыдущий, за исключением добавления вызова time.sleep (1)
в тело нашего цикла задач. Это добавляет задержку в одну секунду к каждой итерации цикла задачи. Задержка была добавлена для имитации влияния медленного процесса ввода-вывода, происходящего в нашей задаче.
Я также включил простой класс прошедшего времени для обработки функций времени начала / прошедшего времени, используемых в отчетах.
"" " example_3.py Просто короткий пример, демонстрирующий простой конечный автомат на Python. Однако у этого есть задержки, которые влияют на него. "" " время импорта очередь импорта из библиотеки.elapsed_time импорт ET def задача (имя, очередь): пока не queue.empty (): count = queue.get () всего = 0 et = ET () для x в диапазоне (количество): print (f'Task {имя} выполняется ') время сна (1) всего + = 1 урожай print (f'Task {name} total: {total} ') print (f'Task {имя} общее затраченное время: {et () :. 1f} ') def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Очередь() # поставьте "работу" в очередь для работы в [15, 10, 5, 2]: work_queue.put (работа) задачи = [ задача ('One', work_queue), задача ('Два', work_queue) ] # запускаем планировщик для выполнения задач et = ET () done = Ложь пока не сделано: за t в задачах: пытаться: Следующий т) кроме StopIteration: tasks.remove (t) если len (tasks) == 0: done = True Распечатать() print ('Общее прошедшее время: {}'.формат (et ())) если __name__ == '__main__': главный()
Когда эта программа запускается, выходные данные показывают, что и первая, и вторая задача выполняются, потребляя работу из очереди и обрабатывая ее, как и раньше. С добавлением фиктивной задержки ввода-вывода мы видим, что наш совместный параллелизм ничего нам не дал, задержка останавливает обработку всей программы, а ЦП просто ждет окончания задержки ввода-вывода.
Это именно то, что подразумевается под «блокирующим кодом» в асинхронной документации.Обратите внимание на время, необходимое для выполнения всей программы, это совокупное время всех задержек. Это еще раз показывает, что так вести дела - не победа.
Пример 4: Кооперативный параллелизм с неблокирующими вызовами (gevent)
Следующая версия программы ( example_4.py
) была немного изменена. Он использует модуль асинхронного программирования gevent прямо в верхней части программы. Модуль импортируется вместе с модулем под названием monkey
.
Затем вызывается метод модуля monkey
, patch_all ()
. Что, черт возьми, это делает? Простое объяснение состоит в том, что он устанавливает программу таким образом, чтобы любой другой импортированный модуль, имеющий блокирующий (синхронный) код, был «исправлен», чтобы сделать его асинхронным.
Как и большинство простых объяснений, это не очень помогает. В отношении нашего примера программы это означает, что time.sleep (1)
(наша фиктивная задержка ввода-вывода) больше не «блокирует» программу. Вместо этого он совместно передает управление системе.Обратите внимание, что оператор yield из example_3.py
больше не присутствует, теперь он является частью вызова time.sleep (1)
.
Итак, если функция time.sleep (1)
была пропатчена gevent, чтобы уступить управление, то куда идет этот элемент управления? Одним из эффектов использования gevent является запуск потока цикла обработки событий в программе. Для наших целей это похоже на цикл «запустить задачи» из example_3.py
. Когда задержка time.sleep (1)
заканчивается, он возвращает управление следующему исполняемому оператору после времени .инструкция sleep (1)
. Преимущество такого поведения заключается в том, что ЦП больше не блокируется задержкой, но может выполнять другой код.
Наш цикл «Выполнить задачи» больше не существует, вместо этого наш массив задач содержит два вызова gevent.spawn (...)
. Эти два вызова запускают два потока gevent (называемые гринлетами), которые представляют собой легкие микропотоки, которые переключают контекст совместно, а не в результате контекстов переключения системы, как обычные потоки.
Обратите внимание на gevent .joinall (tasks)
сразу после создания наших задач. Этот оператор заставляет нашу программу ждать завершения первой и второй задач. Без этого наша программа продолжила бы выполнение операторов печати, но, по сути, ничего не делала бы.
"" " example_4.py Просто короткий пример, демонстрирующий простой конечный автомат на Python Однако у этого есть задержки, которые влияют на него. "" " импорт Gevent от Gevent импорт обезьяны monkey.patch_all () время импорта очередь импорта из библиотеки.elapsed_time импорт ET def задача (имя, work_queue): пока не work_queue.empty (): count = work_queue.get () всего = 0 et = ET () для x в диапазоне (количество): print (f'Task {имя} выполняется ') время сна (1) всего + = 1 print (f'Task {name} total: {total} ') print (f'Task {имя} общее затраченное время: {et () :. 1f} ') def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Очередь() # поставьте "работу" в очередь для работы в [15, 10, 5, 2]: work_queue.put (работа) # запускаем задачи et = ET () задачи = [ gevent.spawn (задача, 'Один', work_queue), gevent.spawn (задача, 'Два', work_queue) ] gevent.joinall (задачи) Распечатать() print (f'Общее истекшее время: {et () :. 1f} ') если __name__ == '__main__': главный()
Когда эта программа запускается, обратите внимание, что первая и вторая задачи запускаются одновременно, а затем ждите фиктивного вызова ввода-вывода. Это индикация времени .sleep (1) вызов
больше не блокируется, другая работа выполняется.
В конце программы обратите внимание на общее прошедшее время, это, по сути, половина времени, которое потребовалось для запуска example_3.py
. Теперь мы начинаем видеть преимущества асинхронной программы.
Возможность одновременного выполнения двух или более задач за счет неблокирующего выполнения процессов ввода-вывода. Используя гринлеты gevent и контролируя переключение контекста, мы можем без особых проблем выполнять мультиплексирование между задачами.
Пример 5: Синхронная (блокирующая) загрузка HTTP
Следующая версия программы ( example_5.py
) - это своего рода шаг вперед и шаг назад. Программа сейчас выполняет некоторую реальную работу с реальным вводом-выводом, выполняя HTTP-запросы к списку URL-адресов и получая содержимое страницы, но делает это блокирующим (синхронным) способом.
Мы изменили программу, чтобы импортировать замечательный модуль запросов и
для выполнения фактических HTTP-запросов, и добавили в очередь список URL-адресов, а не чисел.Внутри задачи вместо увеличения счетчика мы используем модуль запросов, чтобы получить содержимое URL, полученного из очереди, и распечатать, сколько времени потребовалось для этого.
"" " example_5.py Просто короткий пример, демонстрирующий простой конечный автомат на Python Эта версия выполняет фактическую работу, загружая содержимое URL получает из очереди "" " очередь импорта запросы на импорт из lib.elapsed_time импортировать ET def задача (имя, work_queue): пока не work_queue.empty (): url = work_queue.получать() print (f'Task {name} получение URL: {url} ') et = ET () request.get (URL) print (f'Task {name} получил URL: {url} ') print (f'Task {имя} общее затраченное время: {et () :. 1f} ') урожай def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Queue () # поставьте "работу" в очередь для URL в [ "http://google.com", "http://yahoo.com", "http://linkedin.com", "http: // shutterfly.com ", "http://mypublisher.com", "http://facebook.com" ]: work_queue.put (URL) задачи = [ задача ('One', work_queue), задача ('Два', work_queue) ] # запускаем планировщик для выполнения задач et = ET () done = Ложь пока не сделано: за t в задачах: пытаться: Следующий т) кроме StopIteration: tasks.remove (t) если len (tasks) == 0: done = True Распечатать() print (f'Общее истекшее время: {et () :.1f} ') если __name__ == '__main__': главный()
Как и в более ранней версии программы, мы используем выход yield
, чтобы превратить нашу функцию задачи в генератор, и выполнить переключение контекста, чтобы разрешить выполнение другого экземпляра задачи.
Каждая задача получает URL-адрес из рабочей очереди, получает содержимое страницы, на которую указывает URL-адрес, и сообщает, сколько времени потребовалось для получения этого содержимого.
Как и раньше, выход yield
позволяет запускать обе наши задачи, но поскольку эта программа выполняется синхронно, каждое запросов.get ()
блокирует процессор до тех пор, пока страница не будет получена. Обратите внимание на общее время выполнения всей программы в конце, это будет иметь значение для следующего примера.
Пример 6: Асинхронная (неблокирующая) загрузка HTTP с gevent
Эта версия программы ( example_6.py
) изменяет предыдущую версию, чтобы снова использовать модуль gevent. Помните, что вызов gevent monkey.patch_all ()
изменяет все следующие модули, поэтому синхронный код становится асинхронным, это включает запросов
.
Теперь задачи были изменены, чтобы удалить вызов yield
, потому что вызов requests.get (url)
больше не блокирует, а выполняет переключение контекста обратно в цикл событий gevent. В разделе «Выполнить задачу» мы используем gevent для создания двух экземпляров генератора задач, затем используем joinall ()
, чтобы дождаться их завершения.
"" " example_6.py Просто короткий пример, демонстрирующий простой конечный автомат на Python Эта версия выполняет фактическую работу, загружая содержимое URL он получает из очереди.Он также использует gevent для получения URL-адреса в асинхронном режиме. "" " импорт Gevent от Gevent импорт обезьяны monkey.patch_all () очередь импорта запросы на импорт из lib.elapsed_time импортировать ET def задача (имя, work_queue): пока не work_queue.empty (): url = work_queue.get () print (f'Task {name} получение URL: {url} ') et = ET () request.get (URL) print (f'Task {name} получил URL: {url} ') print (f'Task {имя} общее затраченное время: {et () :. 1f} ') def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Очередь() # поставьте "работу" в очередь для URL в [ "http://google.com", "http://yahoo.com", "http://linkedin.com", "http://shutterfly.com", "http://mypublisher.com", "http://facebook.com" ]: work_queue.put (URL) # запускаем задачи et = ET () задачи = [ gevent.spawn (задача, 'Один', work_queue), gevent.spawn (задача, 'Два', work_queue) ] gevent.joinall (задачи) Распечатать() print (f'Общее истекшее время: {et () :.1f} ') если __name__ == '__main__': главный()
В конце выполнения этой программы взгляните на общее время и отдельные времена, чтобы получить содержимое URL-адресов. Вы увидите, что общее время на минус , чем суммарное время всех вызовов requests.get ()
.
Это связано с тем, что эти вызовы выполняются асинхронно, поэтому мы эффективно используем преимущества ЦП, позволяя ему выполнять несколько запросов одновременно.
Пример 7: Асинхронная (неблокирующая) загрузка HTTP с использованием Twisted
Данная версия программы ( example_7.py
) использует модуль Twisted, чтобы делать то же самое, что и модуль gevent, загружать содержимое URL без блокировки.
Twisted - очень мощная система, использующая принципиально иной подход к созданию асинхронных программ. Если gevent модифицирует модули, чтобы сделать их синхронный код асинхронным, Twisted предоставляет собственные функции и методы для достижения тех же целей.
Где example_6.py
использовал пропатченный вызов requests.get (url)
для получения содержимого URL-адресов, здесь мы используем функцию Twisted getPage (url)
.
В этой версии декоратор функции @ defer.inlineCallbacks
работает вместе с yield getPage (url)
для выполнения переключения контекста в цикл событий Twisted.
В самом деле, цикл событий подразумевался, но в Twisted он явно предоставляется строкой оператора actor.run ()
в нижней части программы.
"" " example_7.py Просто короткий пример, демонстрирующий простой конечный автомат на Python Эта версия выполняет фактическую работу, загружая содержимое URL-адрес, который он получает из work_queue.В этой версии используется Twisted фреймворк для обеспечения параллелизма "" " из twisted.internet отложить импорт from twisted.web.client import getPage из twisted.internet импортный реактор, задача очередь импорта из lib.elapsed_time импортировать ET @ defer.inlineCallbacks def my_task (name, work_queue): пытаться: пока не work_queue.empty (): url = work_queue.get () print (f'Task {name} получение URL: {url} ') et = ET () yield getPage (URL) print (f'Task {name} получил URL: {url} ') print (f'Task {name} общее затраченное время: {et () :.1f} ') кроме исключения как e: печать (str (e)) def main (): "" " Это основная точка входа в программу "" " # создаем work_queue для 'work' work_queue = очередь.Queue () # поместите некоторую "работу" в work_queue для URL в [ б "http://google.com", б "http://yahoo.com", б "http://linkedin.com", b "http://shutterfly.com", b "http://mypublisher.com", б "http://facebook.com" ]: work_queue.put (URL) # запускаем задачи et = ET () отложить.DeferredList ([ task.deferLater (реактор, 0, my_task, 'Один', work_queue), task.deferLater (реактор, 0, my_task, 'Два', work_queue) ]). addCallback (лямбда _: response.stop ()) # запускаем цикл событий реактор.run () Распечатать() print (f'Общее истекшее время: {et () :. 1f} ') если __name__ == '__main__': главный()
Обратите внимание, что конечный результат такой же, как и у версии gevent, общее время выполнения программы меньше, чем совокупное время для каждого URL-адреса, который должен быть получен.
Пример 8: Асинхронная (неблокирующая) загрузка HTTP с использованием витых обратных вызовов
Данная версия программы ( example_8.py
) также использует библиотеку Twisted, но демонстрирует более традиционный подход к использованию Twisted.
Под этим я подразумеваю, что вместо использования стиля кодирования @ defer.inlineCallbacks
/ yield
, эта версия использует явные обратные вызовы. «Обратный вызов» - это функция, которая передается в систему и может быть вызвана позже в ответ на событие. В приведенном ниже примере функция success_callback ()
предоставляется Twisted для вызова после завершения вызова getPage (url)
.
Обратите внимание, что в программе декоратор @ defer.inlineCallbacks
больше не присутствует в функции my_task ()
. Кроме того, функция выдает переменную с именем d
, сокращенно от того, что называется отложенным, что и возвращается при вызове функции getPage (url)
.
Отложенный - это способ обработки асинхронного программирования в Twisted, к которому привязан обратный вызов. Когда этот отложенный «срабатывает» (когда getPage (url)
завершается), функция обратного вызова будет вызвана с переменными, определенными во время присоединения обратного вызова.
"" " example_8.py Просто короткий пример, демонстрирующий простой конечный автомат на Python Эта версия выполняет фактическую работу, загружая содержимое URL он получает из очереди. В этой версии используется Twisted фреймворк для обеспечения параллелизма "" " из twisted.internet отложить импорт from twisted.web.client import getPage из twisted.internet импортный реактор, задача очередь импорта из lib.elapsed_time импортировать ET def success_callback (результаты, имя, URL, и т.д.): print (f'Task {name} получил URL: {url} ') print (f'Task {name} общее затраченное время: {et () :.1f} ') def my_task (имя, очередь): если не queue.empty (): пока не queue.empty (): url = queue.get () print (f'Task {name} получение URL: {url} ') et = ET () d = getPage (URL) d.addCallback (успешный обратный вызов, имя, URL и т. д.) выход d def main (): "" " Это основная точка входа в программу "" " # создаем очередь 'работа' work_queue = очередь.Queue () # поставьте "работу" в очередь для URL в [ б "http: // google.com ", б "http://yahoo.com", б "http://linkedin.com", b "http://shutterfly.com", b "http://mypublisher.com", б "http://facebook.com" ]: work_queue.put (URL) # запускаем задачи et = ET () # создать кооператора coop = task.Cooperator () defer.DeferredList ([ coop.coiterate (my_task ('Один', work_queue)), coop.coiterate (my_task ('Два', work_queue)), ]). addCallback (лямбда _: response.stop ()) # запускаем цикл событий реактор.пробег() Распечатать() print (f'Общее истекшее время: {et () :. 1f} ') если __name__ == '__main__': главный()
Конечный результат выполнения этой программы такой же, как и в предыдущих двух примерах, общее время программы меньше совокупного времени получения URL-адресов.
Используете ли вы gevent или Twisted - это вопрос личных предпочтений и стиля программирования. Оба являются мощными библиотеками, которые предоставляют механизмы, позволяющие программисту создавать асинхронный код.
Заключение
Надеюсь, это помогло вам увидеть и понять, где и чем может быть полезно асинхронное программирование.Если вы пишете программу, вычисляющую PI с точностью до миллионного десятичного знака, асинхронный код вам не поможет.
Однако, если вы пытаетесь реализовать сервер или программу, которая выполняет значительный объем операций ввода-вывода, это может иметь огромное значение. Это мощный метод, который может вывести ваши программы на новый уровень.
Асинхронный и неблокирующий ввод-вывод - документация Tornado 6.1
Веб-функции в реальном времени требуют долговременного, в основном простаивающего соединения на
Пользователь.На традиционном синхронном веб-сервере это подразумевает выделение
по одному потоку для каждого пользователя, что может быть очень дорого.
Чтобы свести к минимуму стоимость одновременных подключений, Tornado использует
однопоточный цикл событий. Это означает, что весь код приложения
должен быть асинхронным и неблокирующим, потому что только один
операция может быть активна одновременно.
Термины асинхронный и неблокирующий тесно связаны и
часто используются как взаимозаменяемые, но это не совсем одно и то же.
Блокировка
Функция блокирует , когда ожидает, что что-то произойдет раньше.
возвращение. Функция может блокироваться по многим причинам: сетевой ввод-вывод, диск
Ввод / вывод, мьютексы и т. Д. Фактически, на каждые функциональных блоков, по крайней мере,
немного, пока он работает и использует процессор (для крайних
пример, демонстрирующий, почему к блокировке ЦП нужно относиться так серьезно
как и другие виды блокировки, рассмотрите такие функции хеширования паролей, как
bcrypt, которые по замыслу используют
сотни миллисекунд процессорного времени, намного больше, чем в обычной сети
или доступ к диску).
Функция может быть блокирующей в некоторых отношениях и неблокирующей в некоторых отношениях.
другие. В контексте Торнадо мы обычно говорим о
блокировка в контексте сетевого ввода-вывода, хотя все виды блокировки
должны быть сведены к минимуму.
Асинхронный
Асинхронная функция возвращается до завершения, и
обычно вызывает некоторую работу в фоновом режиме перед
запуск некоторого будущего действия в приложении (в отличие от обычного
синхронных функций, которые делают все, что они собираются делать
перед возвращением).Есть много стилей асинхронных интерфейсов:
- Аргумент обратного вызова
- Вернуть заполнитель (
Future
,Promise
,Deferred
) - Доставить в очередь
- Реестр обратных вызовов (например, сигналы POSIX)
Независимо от того, какой тип интерфейса используется, асинхронные функции
по определению по-разному взаимодействуют со своими абонентами; здесь нет
бесплатный способ сделать синхронную функцию асинхронной таким образом, чтобы
прозрачен для вызывающих (такие системы, как gevent, используют легкие потоки для обеспечения производительности
сопоставимы с асинхронными системами, но на самом деле они не делают
вещи асинхронные).
Асинхронные операции в Tornado обычно возвращают заполнитель
объекты ( Futures
), за исключением некоторых низкоуровневых компонентов
как IOLoop
, которые используют обратные вызовы. Фьючерсы
обычно
преобразованы в их результат с помощью await
или yield
ключевые слова.
Примеры
Вот пример синхронной функции:
из tornado.httpclient import HTTPClient def synchronous_fetch (url): http_client = HTTPClient () ответ = http_client.получить (URL) вернуть response.body
А вот та же функция, переписанная асинхронно как нативная сопрограмма:
из tornado.httpclient import AsyncHTTPClient async def asynchronous_fetch (url): http_client = AsyncHTTPClient () ответ = ждать http_client.fetch (URL) вернуть response.body
Или для совместимости со старыми версиями Python, используя модуль tornado.gen
:
из tornado.httpclient import AsyncHTTPClient от генерации импорта торнадо @gen.сопрограмма def async_fetch_gen (URL): http_client = AsyncHTTPClient () response = yield http_client.fetch (url) поднять gen.Return (response.body)
Сопрограммы немного волшебны, но внутренне они делают что-то вроде этого:
от торнадо. Одновременный импорт Будущее def async_fetch_manual (URL): http_client = AsyncHTTPClient () my_future = будущее () fetch_future = http_client.fetch (URL) def on_fetch (f): my_future.set_result (f.result (). body) fetch_future.add_done_callback (on_fetch) вернуть my_future
Обратите внимание, что сопрограмма возвращает свой Future
до того, как выборка будет
сделано. Это то, что делает сопрограммы асинхронными .
Все, что вы можете делать с сопрограммами, вы также можете делать, передавая
объекты обратного вызова, но сопрограммы предоставляют важные
упрощение, позволяя вам организовать свой код так же, как вы
если бы это было синхронно. Это особенно важно при ошибке
обработки, так как попробуйте
/, за исключением
блоков, которые работают так, как вы ожидаете в
сопрограммы, в то время как этого трудно достичь с помощью обратных вызовов.Более подробно сопрограммы будут рассмотрены в следующем разделе этой статьи.
гид.
Синтаксис
- почему языки программирования автоматически не управляют синхронной / асинхронной проблемой?
Проблема, которую вы описываете, двоякая.
- Программа, которую вы пишете, должна вести себя асинхронно в целом при просмотре извне .
- На месте вызова должно быть видно , а не , независимо от того, теряет ли вызов функции контроль или нет.
Есть несколько способов добиться этого, но в основном они сводятся к
.
- с несколькими потоками (на некотором уровне абстракции)
- имеет несколько видов функций на уровне языка, каждый из которых называется так:
foo (4, 7, bar, quux)
.
Для (1) я объединяю разветвление и запуск нескольких процессов, порождающих несколько потоков ядра и реализации зеленых потоков, которые планируют потоки уровня времени выполнения на потоках ядра.С точки зрения проблемы они одинаковы. В этом мире, , ни одна функция никогда не уступает или теряет контроль с точки зрения своего потока . Сам поток иногда не имеет контроля, а иногда не работает, но вы не отказываетесь от контроля над своим собственным потоком в этом мире. Система, соответствующая этой модели, может иметь или не иметь возможность создавать новые потоки или присоединяться к существующим потокам. Система, подходящая для этой модели, может иметь, а может и не иметь возможность дублировать нить, как форк Unix .
(2) интересно. Чтобы отдать должное, нужно поговорить о формах внедрения и ликвидации.
Я собираюсь показать, почему неявное await
нельзя добавить в такой язык, как Javascript, обратно совместимым способом. Основная идея заключается в том, что, раскрывая обещания пользователю и различая синхронный и асинхронный контексты, Javascript пропустил детали реализации, которые предотвращают единообразную обработку синхронных и асинхронных функций.Также существует тот факт, что вы не можете await
обещание вне тела асинхронной функции. Эти варианты дизайна несовместимы с «невидимой для вызывающей стороны асинхронностью».
Вы можете ввести синхронную функцию с помощью лямбда и устранить ее с помощью вызова функции.
Введение в синхронную функцию:
((x) => {return x + x;})
Устранение синхронной функции:
f (4)
((x) => {return x + x;}) (4)
Вы можете противопоставить это введению и исключению асинхронных функций.
Введение в асинхронную функцию
(async (x) => {return x + x;})
Устранение асинхронной функции (примечание: действительно только внутри функции async
)
ожидание (async (x) => {return x + x;}) (4)
Основная проблема здесь в том, что асинхронная функция также является синхронной функцией, создающей объект обещания .
Вот пример синхронного вызова асинхронной функции в узле.js repl.
> (async (x) => {return x + x;}) (4)
Обещание {8}
Вы можете гипотетически иметь язык, даже динамически типизированный, где разница между асинхронными и синхронными вызовами функций не видна на месте вызова и, возможно, не видна на сайте определения.
Взять такой язык и понизить его до Javascript возможно, вам просто нужно эффективно сделать все функции асинхронными.
Асинхронное программирование на JavaScript • JavaScript для нетерпеливых программистов (версия ES2021)
(Объявление, не блокируйте.)
39 Асинхронное программирование на JavaScript
В этой главе объясняются основы асинхронного программирования на JavaScript.
39.1 План асинхронного программирования на JavaScript
В этом разделе представлена дорожная карта по асинхронному программированию на JavaScript.
Не беспокойтесь о деталях!
Не волнуйтесь, если вы еще не все поняли. Это всего лишь быстрый взгляд на то, что происходит.
39.1.1 Синхронные функции
Нормальные функции - это синхронные : вызывающий ожидает, пока вызываемый объект не закончит свои вычисления. DivideSync ()
в строке A - это синхронный вызов функции:
function main () {
пытаться {
const результат = divSync (12, 3); // (А)
assert.equal (результат, 4);
} catch (err) {
assert.fail (ошибка);
}
}
39.1.2 JavaScript выполняет задачи последовательно в одном процессе
По умолчанию, задачи JavaScript - это функции, которые выполняются последовательно в одном процессе.Это выглядит так:
while (true) {
const task = taskQueue.dequeue ();
задача(); // запускаем задачу
}
Этот цикл также называется циклом событий , потому что такие события, как щелчок мышью, добавляют задачи в очередь.
Благодаря такому стилю совместной многозадачности мы не хотим, чтобы задача блокировала выполнение других задач, например, пока она ожидает результатов от сервера. В следующем подразделе рассказывается, как поступить в этом случае.
39.1.3 Асинхронные функции на основе обратного вызова
Что делать, если div ()
нужен сервер для вычисления результата? Затем результат должен быть доставлен другим способом: вызывающему абоненту не нужно ждать (синхронно), пока будет готов результат; он должен быть уведомлен (асинхронно), когда он есть. Одним из способов асинхронной доставки результата является предоставление div (),
функции обратного вызова, которую он использует для уведомления вызывающего абонента.
function main () {
divCallback (12, 3,
(эрр, результат) => {
if (err) {
утверждать.сбой (ошибка);
} еще {
assert.equal (результат, 4);
}
});
}
При асинхронном вызове функции:
divCallback (x, y, callback)
Затем происходят следующие шаги:
-
DivideCallback ()
отправляет запрос на сервер. - После этого текущая задача
main ()
завершена, и можно выполнять другие задачи. - Когда приходит ответ от сервера, это либо:
39.1.4 Асинхронные функции на основе обещаний
Обещания - это две вещи:
- Стандартный шаблон, упрощающий работу с обратными вызовами.
- Механизм, на котором построены асинхронных функций (тема следующего подраздела).
Вызов функции на основе обещания выглядит следующим образом.
function main () {
divPromise (12, 3)
.then (результат => assert.equal (результат, 4))
.catch (err => assert.fail (err));
}
39.1.5 Асинхронные функции
Один из способов взглянуть на асинхронные функции - это как лучший синтаксис для кода на основе Promise:
асинхронная функция main () {
пытаться {
const result = ждать divPromise (12, 3); // (А)
assert.equal (результат, 4);
} catch (err) {
assert.fail (ошибка);
}
}
DividePromise ()
, который мы вызываем в строке A, - это та же основанная на Promise функция, что и в предыдущем разделе. Но теперь у нас есть синхронно выглядящий синтаксис для обработки вызова. await
можно использовать только внутри особого вида функции, асинхронной функции (обратите внимание на ключевое слово async
перед ключевым словом function
). await
приостанавливает выполнение текущей асинхронной функции и возвращается из нее. Как только ожидаемый результат готов, выполнение функции продолжается с того места, где оно было остановлено.
39.1.6 Следующие шаги
39.2 Стек вызовов
Каждый раз, когда функция вызывает другую функцию, нам нужно помнить, куда вернуться после завершения последней функции.Обычно это делается через стек - стек вызовов : вызывающий помещает в него место для возврата, а вызываемый абонент переходит в это место после того, как это сделано.
Это пример, когда происходит несколько звонков:
функция h (z) {
const error = new Error ();
console.log (error.stack);
}
функция g (y) {
ч (у + 1);
}
функция f (x) {
г (х + 1);
}
f (3);
// сделано
Изначально перед запуском этого фрагмента кода стек вызовов пуст. После вызова функции f (3)
в строке 11 в стеке есть одна запись:
- Строка 12 (расположение в области верхнего уровня)
После вызова функции g (x + 1)
в строке 9 в стеке есть две записи:
- Строка 10 (место в
f ()
) - Строка 12 (расположение в области верхнего уровня)
После вызова функции h (y + 1)
в строке 6 в стеке есть три записи:
- Строка 7 (расположение в
г ()
) - Строка 10 (место в
f ()
) - Строка 12 (расположение в области верхнего уровня)
Регистрация ошибки
в строке 3 дает следующий вывод:
Ошибка:
в h (файл: // демонстрации / async-js / stack_trace.mjs: 2: 17)
в g (файл: //demos/async-js/stack_trace.mjs: 6: 3)
в f (файл: //demos/async-js/stack_trace.mjs: 9: 3)
в файле: //demos/async-js/stack_trace.mjs: 11: 1
Это так называемая трассировка стека , в которой был создан объект Error
. Обратите внимание, что он записывает, где были совершены звонки, а не места возврата. Создание исключения в строке 2 - это еще один вызов. Вот почему трассировка стека включает местоположение внутри h ()
.
После строки 3 каждая из функций завершается, и каждый раз верхняя запись удаляется из стека вызовов.После того, как функция f
будет выполнена, мы вернемся в область верхнего уровня, и стек будет пуст. Когда фрагмент кода заканчивается, это похоже на неявный возврат
. Если мы рассматриваем фрагмент кода как выполняемую задачу, то возврат с пустым стеком вызовов завершает задачу.
39.3 Цикл событий
По умолчанию JavaScript выполняется в одном процессе - как в веб-браузерах, так и в Node.js. Так называемый цикл событий последовательно выполняет задач (фрагменты кода) внутри этого процесса.Цикл событий изображен на рис. 21.
Рисунок 21: Источники задач добавляют код для выполнения в очередь задач , которая очищается циклом событий .
Две стороны обращаются к очереди задач:
Источники задач добавляют задачи в очередь. Некоторые из этих источников запускаются одновременно с процессом JavaScript. Например, один источник задачи заботится о событиях пользовательского интерфейса: если пользователь где-то щелкает и прослушиватель кликов был зарегистрирован, то вызов этого прослушивателя добавляется в очередь задач.
Цикл событий непрерывно выполняется внутри процесса JavaScript. Во время каждой итерации цикла он берет одну задачу из очереди (если очередь пуста, он ждет, пока ее не очистят) и выполняет ее. Эта задача завершается, когда стек вызовов пуст и возвращается
Следующий код JavaScript является приближением цикла событий:
while (true) {
const task = taskQueue.dequeue ();
задача(); // запускаем задачу
}
39.4 Как избежать блокировки процесса JavaScript
39.4.1 Пользовательский интерфейс браузера можно заблокировать
Многие механизмы пользовательского интерфейса браузеров также выполняются в процессе JavaScript (как задачи). Следовательно, долго выполняющийся код JavaScript может блокировать пользовательский интерфейс. Давайте посмотрим на веб-страницу, которая демонстрирует это. Вы можете опробовать эту страницу двумя способами:
- Вы можете запустить его онлайн.
- Вы можете открыть в репозитории следующий файл с упражнениями:
demos / async-js / blocking.html
Следующий HTML-код является пользовательским интерфейсом страницы:
Заблокировать
Идея состоит в том, что вы нажимаете «Блокировать», и длительный цикл выполняется через JavaScript. Во время этого цикла вы не можете нажать кнопку, потому что процесс браузера / JavaScript заблокирован.
Упрощенная версия кода JavaScript выглядит так:
document.getElementById ('блок')
.addEventListener ('щелчок', doBlock); // (А)
function doBlock (событие) {
// ···
displayStatus ('Блокировка ...');
// ···
сон (5000); // (B)
displayStatus ('Готово');
}
функция сна (миллисекунды) {
const start = Date.now ();
while ((Date.now () - начало) <миллисекунды);
}
function displayStatus (status) {
document.getElementById ('statusMessage')
.textContent = статус;
}
Это ключевые части кода:
- Строка A: мы говорим браузеру вызывать
doBlock ()
при каждом щелчке по элементу HTML, идентификатор которого -, блок
. -
doBlock ()
отображает информацию о состоянии, а затем вызываетsleep ()
, чтобы заблокировать процесс JavaScript на 5000 миллисекунд (строка B). -
sleep ()
блокирует процесс JavaScript, выполняя цикл до тех пор, пока не пройдет достаточно времени. -
displayStatus ()
отображает сообщения о состоянии внутри, идентификатор которого -statusMessage
.39.4.2 Как избежать блокировки браузера?
Есть несколько способов предотвратить блокировку браузера длительной операцией:
Операция может доставить свой результат асинхронно : Некоторые операции, такие как загрузка, могут выполняться одновременно с процессом JavaScript.Код JavaScript, запускающий такую операцию, регистрирует обратный вызов, который вызывается с результатом после завершения операции. Вызов обрабатывается через очередь задач. Этот стиль доставки результата называется асинхронным , потому что вызывающий не ждет, пока будут готовы результаты. Обычные вызовы функций доставляют свои результаты синхронно.
Выполнять длительные вычисления в отдельных процессах: это можно сделать с помощью так называемых веб-воркеров .Веб-воркеры - это тяжеловесные процессы, которые выполняются одновременно с основным процессом. У каждого из них есть собственная среда выполнения (глобальные переменные и т. Д.). Они полностью изолированы и должны передаваться через передачу сообщений. Дополнительную информацию см. В веб-документации MDN.
Делайте перерывы во время долгих вычислений. В следующем подразделе объясняется, как это сделать.
39.4.3 Перерывы
Следующая глобальная функция выполняет свой параметр
обратного вызова
после задержки вмс
миллисекунд (подпись типа упрощена -setTimeout ()
имеет больше возможностей):функция setTimeout (callback: () => void, ms: number): любой
Функция возвращает дескриптор (идентификатор), который можно использовать для сброса тайм-аута (отмены выполнения обратного вызова) с помощью следующей глобальной функции:
функция clearTimeout (дескриптор ?: любой): void
setTimeout ()
доступен как в браузерах, так и в Node.js. В следующем подразделе это показано в действии.setTimeout ()
позволяет задачам делать перерывыДругой способ взглянуть на
setTimeout ()
состоит в том, что текущая задача делает перерыв и продолжается позже через обратный вызов.39.4.4 Семантика выполнения до завершения
JavaScript дает гарантию на задачи:
Каждая задача всегда завершается («выполняется до завершения») перед выполнением следующей задачи.
Как следствие, задачам не нужно беспокоиться об изменении своих данных во время работы над ними ( одновременная модификация ).Это упрощает программирование на JavaScript.
Следующий пример демонстрирует эту гарантию:
console.log («начало»); setTimeout (() => { console.log ('обратный вызов'); }, 0); console.log ('конец'); // Выход: // 'Начните' // 'конец' // обратный вызов
setTimeout ()
помещает свой параметр в очередь задач. Таким образом, параметр выполняется через некоторое время после полного завершения текущего фрагмента кода (задачи).Параметр
мс
только указывает, когда задача помещается в очередь, а не когда именно она выполняется.Он может даже никогда не запуститься - например, если в очереди есть задача, которая никогда не завершается. Это объясняет, почему предыдущий код записывает«конец»
перед«обратный вызов»
, хотя параметрмс
равен0
.39.5 Шаблоны для предоставления асинхронных результатов
Чтобы избежать блокировки основного процесса в ожидании завершения длительной операции, результаты часто доставляются в JavaScript асинхронно. Вот три популярных шаблона для этого:
- События
- Обратный звонок
- Обещания
Первые два шаблона объясняются в следующих двух подразделах.Обещания объясняются в следующей главе.
39.5.1 Доставка асинхронных результатов через события
События по схеме работают следующим образом:
- Они используются для асинхронной доставки значений.
- Они делают это ноль или более раз.
- В этом шаблоне есть три роли:
- Событие (объект) переносит данные, которые должны быть доставлены.
- Приемник событий - это функция, которая принимает события через параметр.
- Источник событий отправляет события и позволяет регистрировать прослушиватели событий.
В мире JavaScript существует множество вариантов этого шаблона. Далее мы рассмотрим три примера.
39.5.1.1 События: IndexedDB
IndexedDB - это база данных, встроенная в веб-браузеры. Это пример его использования:
const openRequest = indexedDB.open ('MyDatabase', 1); // (А) openRequest.onsuccess = (событие) => { const db = событие.target.result; // ··· }; openRequest.onerror = (ошибка) => { console.error (ошибка); };
indexedDB
имеет необычный способ вызова операций:Каждая операция имеет связанный метод создания объектов запроса . Например, в строке A операция - «open», метод -
.open ()
, а объект запроса -openRequest
.Параметры операции предоставляются через объект запроса, а не через параметры метода.Например, прослушиватели событий (функции) хранятся в свойствах
.onsuccess
и.onerror
.Вызов операции добавляется в очередь задач с помощью метода (в строке A). То есть мы настраиваем операцию после того, как ее вызов уже был добавлен в очередь. Только семантика от выполнения до завершения избавляет нас от состояния гонки здесь и гарантирует, что операция выполняется после завершения текущего фрагмента кода.
39.5.1.2 События:
XMLHttpRequest
API
XMLHttpRequest
позволяет нам делать загрузки из веб-браузера. Вот так мы скачиваем файлhttp://example.com/textfile.txt
:const xhr = новый XMLHttpRequest (); // (А) xhr.open ('ПОЛУЧИТЬ', 'http://example.com/textfile.txt'); // (B) xhr.onload = () => {// (C) if (xhr.status == 200) { processData (xhr.responseText); } еще { assert.fail (новая ошибка (xhr.statusText)); } }; xhr.onerror = () => {// (D) assert.fail (новая ошибка («Сетевая ошибка»)); }; xhr.send (); // (E) function processData (str) { assert.equal (str, 'Содержимое текстового файла.txt \ n'); }
С помощью этого API мы сначала создаем объект запроса (строка A), затем настраиваем его, а затем активируем (строка E). Конфигурация состоит из:
- Указание того, какой метод HTTP-запроса использовать (строка B):
GET
,POST
,PUT
и т. Д. - Регистрация слушателя (строка C), который уведомляется, если что-то может быть загружено.Внутри слушателя нам все еще нужно определить, содержит ли загрузка то, что мы запросили, или сообщает нам об ошибке. Обратите внимание, что некоторые данные результатов доставляются через объект запроса
xhr
. (Я не фанат такого смешения входных и выходных данных.) - Регистрация слушателя (строка D), который уведомляется, если произошла сетевая ошибка.
39.5.1.3 События: DOM
Мы уже видели события DOM в действии в §39.4.1 «Пользовательский интерфейс браузера может быть заблокирован».Следующий код также обрабатывает
событий click
:const element = document.getElementById ('моя-ссылка'); // (А) element.addEventListener ('щелчок', clickListener); // (B) function clickListener (событие) { event.preventDefault (); // (C) console.log (event.shiftKey); // (D) }
Сначала мы просим браузер получить HTML-элемент с идентификатором
«my-link»
(строка A). Затем мы добавляем слушателя для всех событийclick
(строка B). В слушателе мы сначала говорим браузеру не выполнять действие по умолчанию (строка C) - переход к цели ссылки.Затем мы регистрируемся в консоли, если в данный момент нажата клавиша Shift (строка D).39.5.2 Доставка асинхронных результатов через обратные вызовы
Обратные вызовы - это еще один шаблон для обработки асинхронных результатов. Они используются только для одноразовых результатов и имеют то преимущество, что они менее подробны, чем события.
В качестве примера рассмотрим функцию
readFile ()
, которая читает текстовый файл и асинхронно возвращает его содержимое. Вот как вы вызываетеreadFile ()
, если он использует Node.обратные вызовы в стиле js:readFile ('some-file.txt', {кодировка: 'utf8'}, (ошибка, данные) => { if (error) { assert.fail (ошибка); возвращаться; } assert.equal (data, 'Содержимое some-file.txt \ n'); });
Есть один обратный вызов, который обрабатывает как успех, так и неудачу. Если первый параметр не
null
, произошла ошибка. В противном случае результат можно найти по второму параметру.Упражнения: код обратного вызова
В следующих упражнениях используются тесты для асинхронного кода, которые отличаются от тестов для синхронного кода.Обратитесь к §10.3.2 «Асинхронные тесты в Mocha» для получения дополнительной информации.
- От синхронного кода к обратному вызову:
упражнения / async-js / read_file_cb_exrc.mjs
- Реализация основанной на обратном вызове версии
.map ()
:упражнения / async-js / map_cb_test.mjs
39.6 Асинхронный код: недостатки
Во многих ситуациях в браузерах или на Node.js у вас нет выбора, вы должны использовать асинхронный код. В этой главе мы увидели несколько шаблонов, которые может использовать такой код.У всех есть два недостатка:
- Асинхронный код более подробный, чем синхронный.
- Если вы вызываете асинхронный код, ваш код тоже должен стать асинхронным. Это потому, что вы не можете синхронно ждать асинхронного результата. Асинхронный код заразителен.
Первый недостаток становится менее серьезным при использовании Promises (рассматривается в следующей главе) и в основном исчезает при использовании асинхронных функций (описанных в следующей главе).