Различия между версиями 1 и 5 (по 4 версиям)
Версия 1 от 2020-12-10 13:39:35
Размер: 6105
Редактор: FrBrGeorge
Комментарий:
Версия 5 от 2020-12-10 15:47:59
Размер: 7357
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 35: Строка 35:
 1. Эшелонируем сортировку с помощью задания тайм-аута (в пятом параметре будем передавать номер ''эшелона'' `n` и ждать `n/c` секунд) и общего `create_task() / gather()`  1. {i} Эшелонируем сортировку с помощью задания тайм-аута (в пятом параметре будем передавать номер ''эшелона'' `n` и ждать `n/c` секунд) и общего `create_task() / gather()`
Строка 38: Строка 38:
  * Пример
Строка 44: Строка 45:
 1. Задача_1: переписать сортировку с использованием `future` для синхронизации (например, `слияние_4_8` должно дожидаться двух фьюч — `фьюча_4_6` и `фьюча_6_8`)
 1. Задача_2: (на дом). Переписать сортировку под произвольный (не слишком большой) объём данных
 1. <!> Задача_1: переписать сортировку с использованием `future` для синхронизации
  * Каждая функция слияния работает так
   * Дожидается фьючи конца слияния правой половины
   * Дожидается фьючи конца слияния левой половины
   * Выполняет слияние
   * Выставляет готовность фьючи конца слияния своего интервала
  * Если слияние вырожденное (1+1), в качестве фьючи передаётся `asyncio.sleep(0)`
  * Фьючи можно делать просто по именам (7 штук, типа `фьюча_4_8`) и передавать их в качестве параметров корутине слияния
  * Фьючи можно положить в массив и научить корутину вычислять, какие именно элементы этого массива — правая и левая фьючи, а какой — фьюча результата
  * Решение при этом будет представлять собой один большой `gather()` на все корутины + один `await фьюча_0_16` или её аналога
  
  '''TODO''' формулировка и формат
 1. <!> Задача_2: (на дом). Переписать сортировку под произвольный (не слишком большой) объём данных
  '''TODO''' формулировка и формат

12.10 Асинхронные возможности Python

Краткий пересказ теории

  • Асинхронная парадигма (вариант реализации): образующий цикл, события и обратные вызовы
  • Python: вместо обратных вызовов — повторный вход в генератор (см. параметрические генераторы), образующий цикл программируйте сами!
  • Асинхронность

    последовательное выполнение ограниченных yield фрагментов кода различных генераторов в порядке, который определяет программист.

    • Образующий цикл согласно какой-то логике выбирает сопрограмма и даёт команду отчёт = сопрограмма.send(команда) для выполнения очередного фрагмента

    • Сопрограмма получает команду с помощью команда = yield(предыдущий отчёт), анализирует её и выполняет следующий фрагмент кода

В действительности:

  • Образующий цикл (со своей логикой) уже реализован кем-то

  • Инструменты управления этой логикой реализованы тем же автором

  • Поэтому пользователи этой действительности не пишут .send() или явный yield

  • Основная конструкция — результат = yield from генератор, который возвращает то, что у генератора написано в return

Синтаксический сахар и асинхронный протокол:

  • Вместо генератора пишем сопрограму с помощью async def. Это тот же генератор, но в нём нельзя пользоваться yield

  • Вместо yield from пишем результат = await сопрограмма (различие в более удобном синтаксисе и в проверке того, сопрограмма с помощью async def)

  • Всё остальное берёт на себя разработчик инструментария:
    1. Образующий цикл
    2. Инструменты управления образующим циклом, которым разрешено делать прямой yield в него

Asyncio

  1. Напишем программу сортировки слиянием массива из 16 элементов
    • Все 15 слияний делать руками с помощью вызова функции слить(начало1, конец1, начало2, конец2)

    • Для слияния используется общий глобальный второй массив
  2. {i} Перетащим их в структуру asyncio.run()/await 

    • Для наглядности снабдим каждый шаг сортировки await asyncio.sleep(0.1) и выводом номера «задания» (передадим его в качестве пятого параметра)

    • Разницы никакой, всё равно запуск последовательный

  3. Для придания асинхронности надо писать свой mainloop. Но он уже есть — это asyncio.run(). Не надо писать свой mainloop, надо пользоваться asyncio.create_task() и asyncio.gather(все 15 слияний)

    • Получается какая-то каша вместо сортировки, почему?
    • {i} Эшелонируем сортировку с помощью нескольких фрагментов вида create_task()… + gather(все_таски_из фрагмента) (палево — их пять)

  4. {i} Эшелонируем сортировку с помощью задания тайм-аута (в пятом параметре будем передавать номер эшелона n и ждать n/c секунд) и общего create_task() / gather()

    • Чем этот подход плох?
  5. Фьюча (future).
    • Пример
    • Алгоритм работы
      1. Awaitable-объект, у которого есть творец и адресат, оба имеют к нему доступ.
      2. Адресат делает результат = await фьюча, и уходит в mainloop.

      3. Творец, когда ему заблагорассудится, с помощью фьюча.set_result(что-то) объявляет mainloop-у, что будущее наступило с результатом что-то

      4. Тогда mainloop, наконец, активизирует эту фьючу и адресат просыпается
    • В действительности, фьюча — это просто генератор на два шага: будушее не наступило / yield / будущее наступило, в котором есть два дополнительных поля (объявление о том, что оно наступило и передаваемое значение)
  6. <!> Задача_1: переписать сортировку с использованием future для синхронизации

    • Каждая функция слияния работает так
      • Дожидается фьючи конца слияния правой половины
      • Дожидается фьючи конца слияния левой половины
      • Выполняет слияние
      • Выставляет готовность фьючи конца слияния своего интервала
    • Если слияние вырожденное (1+1), в качестве фьючи передаётся asyncio.sleep(0)

    • Фьючи можно делать просто по именам (7 штук, типа фьюча_4_8) и передавать их в качестве параметров корутине слияния

    • Фьючи можно положить в массив и научить корутину вычислять, какие именно элементы этого массива — правая и левая фьючи, а какой — фьюча результата
    • Решение при этом будет представлять собой один большой gather() на все корутины + один await фьюча_0_16 или её аналога

      TODO формулировка и формат

  7. <!> Задача_2: (на дом). Переписать сортировку под произвольный (не слишком большой) объём данных

    • TODO формулировка и формат

LecturesCMC/PythonIntro2020/Prac/14_Async (последним исправлял пользователь FrBrGeorge 2020-12-16 12:46:48)