Task.Run(...) действительно всегда отправляет делегат по маршруту TaskScheduler.Default → ThreadPoolTaskScheduler → ThreadPool. И тем самым мы сразу и надёжно отвязываемся от SynchronizationContext.Current.
await DoAsync().ConfigureAwait(false) будет иметь эффект только в случае фактической асинхронности. Например:
Приостанавливает (suspend) означает, что метод (сопрограмма) подписывает себя на асинхронное продолжение (continuation) и выходит (делает return), освобождая поток.
Синхронный код ждёт, занимая/блокируя поток через busy wait или примитивы синхронизации ОС.
Скорее всего, вы имеете в виду отсутствие параллелизма в пределах метода (типа WhenAll или ForAsync). От этого ни сам метод, ни дочерние вызовы не перестают быть асинхронными. Хронологически, между Read и Write может успеть выполниться часть другого асинхронного метода. Другими словами, может случиться кооперативная многозадачность на уровне приложения (как раз то, зачем придумали async/await).
гораздо эффективнее и проще вызвать аналогичную синхронную функцию
Я бы не рискнул давать такой совет хотя бы потому, что мы не знаем конкретного call-стека. В контексте статьи спорить не о чем - здесь код лишь иллюстрирует преобразование компилятора.
Цель - "понять, как работает async/await" (это написано в заголовке статьи).
Вы пишете про самый первый пример: "зачем-то асинхронные функции вызываются синхронно". Но ведь это не так. В нём асинхронно вызываются асинхронные функции - await File.XxxAllTextAsync.
Магия async/await (то есть преобразование кода, проводимое компилятором) никогда не создаёт потоки сама. Она только комбинирует результаты других вызовов через GetAwaiter и AsyncXXXMethodBuilder. При этом даже тип Task не обязателен - см. Generalized async return types and ValueTask.
Зато легко отлаживать. Вначале я запускал этот тул на локальной машине, долго гонял и наблюдал, а потом уже пересадил в облако. Легко добавлять любые дополнительные условия и костыли.
Здесь я имею в виду не сами концепции пулл-реквестов и ревью, а то как они реализованы в гитхабовском UI.
Были ли еще какие-то причины? Потому, что сейчас мне видится только бесплатная разработка/поддержка со стороны пользователей GitHub этого набора компонентов.
Вклад со стороны сообщества — не главная причина. В CONTRIBUTING мы честно говорим, что не обещаем принимать каждый PR. В первую очередь, мы хотим стать ближе к frontend-разработчикам, дать пользователям возможность получать фиксы и новые фичи, не дожидаясь официальных релизов (в идеале, прийти к continuous delivery). Для DevExtreme же, как для продукта, это бесценная быстрая обратная связь.
runit, используемый в качестве менеджера процессов, очень неудобен в использовании, особенно когда что-то идёт не так. Supervisord куда более приятен и к тому же сам умеет делать «reape unknown pid», так что «изобретения» в виде my_init не нужны.
Ни ssh, ни nsenter теперь не являются необходимыми. Для входа в контейнер используется команда docker exec -ti CONTAINER_ID bash. Для более удобной работы в консоли внутри контейнера (запуск mc и тп.) рекомендую добавить в Dockerfile:
ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 TERM=xterm
RUN locale-gen $LC_ALL
Самое опасное: cron и logrotate пускаются со стандартными конфигами, не рассчитанными на работу в контейнерах. Пример: установили Apache, получили файл /etc/logrotate.d/apache2, внутри которого используется /etc/init.d, значит runit потеряет контроль над процессом после первой ротации логов.
1 3 ms 2 ms 2 ms
2 27 ms 26 ms 26 ms
3 33 ms 28 ms 28 ms
4 30 ms 31 ms 27 ms
5 33 ms 31 ms 32 ms 77.51.254.234
6 90 ms 74 ms 74 ms ae-5.626.m7-cr1-b.msk.ip.rostelecom.ru [188.254.36.101]
7 133 ms 144 ms 136 ms 95.167.91.155
8 174 ms 162 ms 166 ms 61.213.146.253
9 185 ms 185 ms 162 ms ae-0.r23.tokyjp01.jp.bb.gin.ntt.net [129.250.4.106]
10 236 ms 232 ms 231 ms as-6.r21.sngpsi02.sg.bb.gin.ntt.net [129.250.5.157]
11 233 ms 225 ms 241 ms ae-4.r20.sngpsi02.sg.bb.gin.ntt.net [129.250.6.100]
12 227 ms 226 ms 228 ms 116.51.27.150
13 299 ms 226 ms 225 ms 103.253.144.242
14 246 ms 254 ms 246 ms 128.199.244.8
Ping statistics for 128.199.244.8:
Minimum = 247ms, Maximum = 251ms, Average = 249ms
Автор хотел более доходчиво донести «физику явления». А формулы и их выводы можно в книжках посмотреть. Мне, например, очень понравилась часть статьи, где объясняется, почему применение окон приводит к растеканию спектра.
Раздел с PDF-ами доступен, но не уверен, что в них есть ответ на мой вопрос. Интересует документация в духе такой или такой.
Там легко понять, что для Chrome Store нужно загрузить zip c иконкой и манифестом, а для Firefox Marketplace просто указать ссылку на .webapp-файл. Что делать для Tizen? В панели разработчика просят загрузить абстрактный Binary File.
Есть ли хотя бы минимальный туториал о том, как опубликовать hosted-приложение в store? Гугление по «tizen hosted applications» не дает практически ничего.
Цель демки Kitchen Sink — показать доступный арсенал UI-элементов, а не производительность. В плане производительности же, скажем прямо, есть куда копать.
Продукт будет развиваться, и с выходом новых версий будет обновляться идущий в комплекте jQuery. В своем проекте разработчик может подложить версию поновее самостоятельно, главное не напороться на несовместимости (например, мы знаем что не всякая версия Knockout совместима с jQuery)
Есть неточности. Вот как правильно:
Task.Run(...)
действительно всегда отправляет делегат по маршрутуTaskScheduler.Default
→ThreadPoolTaskScheduler
→ThreadPool
. И тем самым мы сразу и надёжно отвязываемся отSynchronizationContext.Current
.await DoAsync().ConfigureAwait(false)
будет иметь эффект только в случае фактической асинхронности. Например:Поэтому
ConfigureAwait
приходится дописывать каждый раз, к каждомуawait
.И с терминологией важно не путаться:
SynchronizationContext
- контекст синхронизации - планировщик, в который отправляются await continuations.ExecutionContext
- контекст выполнения - место хранения async locals.Приостанавливает (suspend) означает, что метод (сопрограмма) подписывает себя на асинхронное продолжение (continuation) и выходит (делает return), освобождая поток.
Синхронный код ждёт, занимая/блокируя поток через busy wait или примитивы синхронизации ОС.
Скорее всего, вы имеете в виду отсутствие параллелизма в пределах метода (типа
WhenAll
илиForAsync
). От этого ни сам метод, ни дочерние вызовы не перестают быть асинхронными. Хронологически, междуRead
иWrite
может успеть выполниться часть другого асинхронного метода. Другими словами, может случиться кооперативная многозадачность на уровне приложения (как раз то, зачем придумалиasync/await
).Я бы не рискнул давать такой совет хотя бы потому, что мы не знаем конкретного call-стека. В контексте статьи спорить не о чем - здесь код лишь иллюстрирует преобразование компилятора.
Цель - "понять, как работает async/await" (это написано в заголовке статьи).
Вы пишете про самый первый пример: "зачем-то асинхронные функции вызываются синхронно". Но ведь это не так. В нём асинхронно вызываются асинхронные функции -
await File.XxxAllTextAsync
.И правда, моя формулировка получилась слишком общей. Добавил уточнение:
Магия
async/await
(то есть преобразование кода, проводимое компилятором) никогда не создаёт потоки сама. Она только комбинирует результаты других вызовов черезGetAwaiter
иAsyncXXXMethodBuilder
. При этом даже типTask
не обязателен - см. Generalized async return types and ValueTask.Зато легко отлаживать. Вначале я запускал этот тул на локальной машине, долго гонял и наблюдал, а потом уже пересадил в облако. Легко добавлять любые дополнительные условия и костыли.
Здесь я имею в виду не сами концепции пулл-реквестов и ревью, а то как они реализованы в гитхабовском UI.
Вклад со стороны сообщества — не главная причина. В CONTRIBUTING мы честно говорим, что не обещаем принимать каждый PR. В первую очередь, мы хотим стать ближе к frontend-разработчикам, дать пользователям возможность получать фиксы и новые фичи, не дожидаясь официальных релизов (в идеале, прийти к continuous delivery). Для DevExtreme же, как для продукта, это бесценная быстрая обратная связь.
echo
, т.к. обходятся только запущенные контейнеры.docker exec -ti CONTAINER_ID bash
. Для более удобной работы в консоли внутри контейнера (запуск mc и тп.) рекомендую добавить в Dockerfile:/etc/logrotate.d/apache2
, внутри которого используется/etc/init.d
, значит runit потеряет контроль над процессом после первой ротации логов.После установки создайте файл /etc/dnsmasq.d/docker с контентом
Теперь после добавления нового контейнера или пересоздания/перезапуска существующего надо будет выполнить примерно такой скрипт:
Минусы:
Плюсы:
Идея взята отсюда.
Сигнал ограничен во времени => спектр растекается (см. Benedicks's theorem). Спектр растекается => невозможно применить теорему Котельникова.
Там легко понять, что для Chrome Store нужно загрузить zip c иконкой и манифестом, а для Firefox Marketplace просто указать ссылку на .webapp-файл. Что делать для Tizen? В панели разработчика просят загрузить абстрактный Binary File.
Уточню: интересуют именно hosted web-приложения.