Pull to refresh
3
0
Ильмир Усманов @ilmirus

User

Send message
Это в принципе не верно.

Назовите хотя бы одну ОС, в которой потоки/треды реализованы не через приостановку вычислений вне зависимости от того, что этот поток сейчас делает. Где здесь автомат? ОС может остановить поток в (теоретически) любой ассемблерной инструкции. Или вы каждую инструкцию собираетесь сделать состоянием в автомате?


Есть параллельное программирование, которое может быть асинхронным или синхронным

А как быть с однопоточной асинхронной моделью (как вы могли про нее не слышать? В каком манямирке вы живете?). И, разумеется, многопоточный != параллельный. Вот хорошее объяснение: https://codewala.net/2015/07/29/concurrency-vs-multi-threading-vs-asynchronous-programming-explained/.


Вычисления создает блок-схемная модель

Да хоть Господь Бог. Это не имеет значения ни для потоков, ни для корутин. Почти любой код можно преобразовать в приостанавливаемый. Посмотрите, как те же корутины реализованы в go. В kotlin они реализованы с явными точками останова, но это особенности реализации, иначе было сделать нельзя. В go же таких проблем нет и там нет явных точек останова, совсем как в потоках. Где, черт возьми, здесь автоматы?


И давайте меньше оглядываться на «запад»,

А давайте вы не будете разглагольствовать с умным видом о том, в чем очевидно не разбираетесь. У меня еще была надежда, что вы просто ни разу не программировали на языке с корутинами, но эта надежда уже развеялась после "автоматы реализуют потоки, автоматы реализуют сопрограммы". Это уже давно не так, и, скорее всего, лет как минимум 40 не так. Те же потоки линукса как пруф (возьмите любой словарь английского, хоть 50-го года издания и посмотрите значение слова proof).


Это азы теории.

Когда теория расходится с наблюдениями, теорию принято дополнять, а не игнорировать наблюдения. Это азы эпистомологии.


больше работать своей головой

Я за. Только когда это работает в обе стороны. Давайте вы сначала посмотрите как реализованы корутины хотя бы в двух языках, скажем, в kotlin и go, а также как реализованы потоки в линуксе, найдете 10 отличий корутин в go от потоков в линуксе, потом мы возобновим беседу, иначе это разговор немого с незнающим.


И да, я не могу игнорировать "запад", я живу на "западе". И я все еще не увидел реализации structured concurrency на автоматах. Ответы без ссылки на реализацию я буду впредь игнорировать. Не вижу смысла спорить без железных аргументов, ваши "верю-не верю, ибо это, мой взгляд, азы" за железные аргументы не сойдут.

Вот корутины — это то, что вы описали, только генерируется компилятором. Каждое состояние — это либо вызов другой корутины либо явное указание, что здесь можно уснуть и передать управление другой корутине и при каком условии надо эту корутину разбудить.


Плюс корутин, по сравнению с автоматным программированием (термин, который я встречал только в отечественном computer science, на западе такого термина нет. Если и был, то он изжил себя. Там ему и место — на свалке истории) в том, что не надо самостоятельно строить автомат. Это сделает компилятор. Точно так же, как от программ с кучей переходов по меткам перешли на структурное программирование, а переходы теперь расставляет компилятор, так и от ручного построения автоматов в 60-80-х перешли на генерацию автоматов компилятором. И даже этого недостаточно. Structured concurrency (даже не просите перевести, не могу. В русском языке нет аналогичного понятия. И даже термин сопрограммы ужасен с точки зрения семантики, потому что программа все равно одна, чему там "со-". Поэтому я использую кальку "корутины", которую можно перевести как "софункции" или "сопроцедуры") решает те же проблемы, что и структурное программирование решало во времена Дейктры — делает понимание чужого кода более простым. Основная идея в том, что если поток/корутина запускает несколько других потоков/корутин, то он/она должен/должна дождаться их работы. Это очень сильно облегчает параллельное и асинхронное программирование, в частности, упрощает обработку ошибок, так как количество состояний, в котором может пребывать программа, уменьшается.


Сейчас разница между корутиной и потоком становится все более и более размытой. В go, D, raku и в назревающем loom (жалко, что я не пишу этот комментарий по-английски, могла бы быть неплохая игра слов), например, корутины ведут себя практически как потоки. Их становится не отличить. В kotlin, c++20, javascript, C# и rust разница между корутинами и потоками еще остается явной.


Пруф — ссылка на код, который реализует structured concurrency, желательно, неявно. Хотя неявно в автоматном программировании невозможно — это все равно, что программировать на языке ассемблера без макроассемблера, ручками считая адреса переходов.

Код теперь понятнее, компактнее

Вот вы и ответили на свой же вопрос


Может, лучше сразу реализовать автоматы?

Сравните


suspend fun dummy() {}

suspend fun bar() {
    for (i in 1..10) {
        dummy()
    }
}

С получившимся


   @Nullable
   public static final Object dummy(@NotNull Continuation $completion) {
      return Unit.INSTANCE;
   }

   @Nullable
   public static final Object bar(@NotNull Continuation $completion) {
      Object $continuation;
      label35: {
         if ($completion instanceof <undefinedtype>) {
            $continuation = (<undefinedtype>)$completion;
            if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
               ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
               break label35;
            }
         }

         $continuation = new ContinuationImpl($completion) {
            // $FF: synthetic field
            Object result;
            int label;
            int I$0;
            int I$1;

            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return JvmKt.bar(this);
            }
         };
      }

      Object $result = ((<undefinedtype>)$continuation).result;
      Object var5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
      int i;
      int var2;
      switch(((<undefinedtype>)$continuation).label) {
      case 0:
         ResultKt.throwOnFailure($result);
         i = 1;
         var2 = 10;
         break;
      case 1:
         var2 = ((<undefinedtype>)$continuation).I$1;
         i = ((<undefinedtype>)$continuation).I$0;
         ResultKt.throwOnFailure($result);
         ++i;
         break;
      default:
         throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
      }

      while(i <= var2) {
         ((<undefinedtype>)$continuation).I$0 = i;
         ((<undefinedtype>)$continuation).I$1 = var2;
         ((<undefinedtype>)$continuation).label = 1;
         if (dummy((Continuation)$continuation) == var5) {
            return var5;
         }

         ++i;
      }

      return Unit.INSTANCE;
   }

Что понятнее и компактнее?


Можно как-то кратко сформулировать отличие? Принципиальное. Вне привязки к языку.

Там же большими буквами название статьи: "Design of a Separable Transition-Diagram Compiler". И там как раз дается определение корутин тогдашних. В чем отличие тогдашних корутин от тогдашних сопрограм? Его нет — это два способа назвать одно и то же. Вот оно, определение, кстати:
Modules which communicate with each other according to the following restrictions:
(I) the only communication between modules is in the form of discrete items of information;
(2) the flow of each of these items is along fixed, one-way paths;
(3) the entire program can be laid out so that the input is at the left extreme, the output is at the right extreme, and everywhere in between all information items flowing between modules have a component of motion to the right.
Сравните это с определением современных корутин: suspendable unit of computation.


По поводу генерации компиляторами. Автомат я ему не доверю.

Могу я узнать причину кроме "я не доверяю компиляторам, лучше уж я ручками"?


Он реализует любой автомат, как отдельный процесс.

То есть у вас по сути акторы. Что опять же, не равно корутинам. Отличие от корутин — корутины могут общаться не только методом передачи сообщений.


нормальные автоматы — все что угодно и влет

"Настоящий шотландец такого никогда не сделает", ага. Если вы такое утверждаете (на автоматах можно сделать structured concurrency), то, разумеется, у вас есть пруфы. "Где пруфы, Билли, нам нужны пруфы".


И да, под сообщением есть ссылка "ответить". Не имеет смысла каждый новый ответ писать на верхнем уровне комментариев.

С разморозкой. Корутины уже не те, что были 60 лет назад.
Я как-то уже пошутил про те корутины, которые были 60 лет назад: https://youtu.be/UzzH4biTEbY?t=117.


Может, лучше сразу реализовать автоматы? Не пробовали?

Может, сразу писать на ассемблере? Не пробовали? Компилятор, в отличие от человека, более внимателен и всегда правильно расставит переходы между состояниями автомата, даже в случае сложного потока управления. И у меня еще был бы вопрос к читаемости получившегося кода, но я привык читать байткод корутин, который генерируется котлиновским компилятором. Вы, кстати, пытались отлаживать кучу автоматного кода? А это то, что я делаю по работе, когда мне присылают баг с прикрепленной ссылкой на гитхаб. Ибо даже минимизировать код, воспроизводящий баг не так-то просто. Да, я тоже человек и мой код тоже содержит ошибки, но после их исправления я могу быть уверен, что в подобных случаях автоматы, генерируемые компилятором будут валидными. Если бы я писал их руками каждый раз и заставлял бы своих пользователей писать их руками, никто бы не использовал корутины.


И сделайте, пожалуйста, что-то вроде structured concurrency https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ на голых автоматах. На корутинах же его возможно сделать (пруф: kotlinx.coroutines).

Когда будете переползать на C++20 и попытаетесь понять, как работают горрутины, вспомните эту статью.

Спасибо за статью! На мой взгляд, покрыто более-менее все однопоточное — continuation, state-machine, spilling-unspilling локальных переменных. Осталось только покрыть ContinuationInterceptor и вся магия котлиновских корутин развеется.


Хорошего описания принципа работы котлиновских корутин я не видел.

Видели ли вы мою лекцию по котлиновским корутинам, которую я читал на Физтехе: https://www.youtube.com/watch?v=UzzH4biTEbY?

Спасибо, включил.


Я считаю что Samsung не имеет никаких внутренних процессов самоконтроля

Забавно, мне тоже вспомнились проблемы у Apple, которые возникали у "small minority of users": bendgate, "you are holding it wrong", клавиатура с механизмом-бабочкой.


У всех бывают факапы. Тут, на мой взгляд, еще важно, как компания, которая допустила факап, реагирует на него. Отзывает ли всю партию, хотя возгорание было только в нескольких случаях или игнорирует, как было с той же "бабочкой". Если компания в ответ на багрепорты в их железе показывает большой средний палец, для меня это сигнал не пользоваться их продукцией.


Ну зачем же себя называть фанбоем

Потому что это именно то, что я чувствую, когда все выше моих ожиданий, как было с моим iPod mini четвертого поколения или с моим Galaxy Note II — фан.

> То есть по вашему Apple не имеет права входить в существующий рынок а только создавать новый?
Этого я не говорил, я говорил, что она разучилась делать инновации. Больше нет той Apple, что подарила миру офигенный iPod с щелкающим колесиком. Вместо нее теперь обычная компания наряду с десятком таких же. Взять пример из статьи — было две компании, которые могли повлиять на рынок персоналных компьютеров, теперь их пересчитывать устанешь. Даже тот же Самсунг пытается делать что-то инновационное — Galaxy Note, лучшая линейка смартфонов (это мое мнение, не обязательно должно совпадать с вашим), Galaxy Fold (посмотрим, во что это выльется), за это его уже можно уважать. За что уважать компанию, которая забыла, что «посредственности копируют, гении воруют» и самозабвенно занимается этим самым копированием? Как бывшему фанбою Apple, мне было больно смотреть, во что она себя превратила. Теперь у меня, как я уже написал, «нелюбовь».
Любопытно, кстати, что Samsung Galaxy Gear появились в сентябре 2013, а Apple Watch ровно через год — в сентябре 2014. Так кто у кого скопировал?
> до Apple Watch никакого рынка умных часов не было вообще
Pebble и компании, создающие часы, соединяющиеся со смартфоном, создали этот рынок, а не Apple. Apple его захватила, но не создала.

Вот скажите, как все, что вы написали, помимо фактической ошибки про Apple Watch, опровергает мой тезис о том, что Apple превратилась в Frito-Lay? Опять-таки, это скорее подтверждает его.
Об этом тоже есть в статье: «Она просто наблюдает за новинками маленьких производителей чипсов, год изучает эти новинки, а еще через год-другой выпускает аналогичный продукт,… и получает все те же 80 процентов нового рынка.»
Занятно, что все ваши аргументы скорее подтверждают точку зрения, что Apple превратился в Frito-Lay, чем опровергают их.
По поводу фокуса на одном продукте есть очень хорошая статья от инженера Apple: tidbits.com/2019/10/21/six-reasons-why-ios-13-and-catalina-are-so-buggy
Спасибо за примеры, которые подтверждают мою точку зрения про догоняющую компанию.
Apple Watch — посмотрели на Pebble Watch и добавили экран побольше.
AirPods — взяли любые из десятков, если не сотен блютус наушников и убрали провод между наушниками, забыв к тому же, что уши у людей разные и некоторым они тупо неудобны.

Хотите еще примеры? Они есть у меня:
Лопатники вместо телефонов, умещающихся в ладони.
Стилус.
Несколько камер на телефонах.
Клавиатура к планшету.
Через пару лет, если складные телефоны взлетят, они «изобретут» складной телефон.

Что остается? Touchbar, который не заменяет функциональных клавиш, потому что нет тактильной отдачи и вырезанный слот для наушников. Хороший результат для компании, «фокусирующей все усилия на одном продукте».
Я не могу говорить за всех, но причина моей нелюбви к Apple описана прямо в статье:
«Становясь многомиллиардными гигантами, компании теряют собственный взгляд. Они начинают плодить звенья между руководителями и теми, кто работает по-настоящему. Они перестают испытывать страсть к своим продуктам. Настоящим творцам, тем, кому не все равно, приходится преодолевать пять уровней менеджеров, чтобы просто делать то, что они считают нужным.
Большинство компаний не могут удержать блестящих специалистов в среде, где индивидуальные достижения не поощряются и даже осуждаются. Эти специалисты уходят, серость остается.»
Они пытаются вести себя как компания, способная создать Apple II, iPhone и, что греха таить, iPad. Но после выхода iPad они превратились в догоняющих:
«Она просто наблюдает за новинками маленьких производителей чипсов, год изучает эти новинки, а еще через год-другой выпускает аналогичный продукт», но уже без идеальной поддержки.
Если вы уж через JNI зовете плюсовые корутины, то в чем проблема звать котлиновские корутины? Нужен асинхронный код — пишем suspend функции в котлине, а из Джавы звать только обертки над ними.
Первая «ошибка»:
УМВР:
fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount)

fun Any.easyPrint() = println(this)

fun main() {
println("Madrigal has left the building".addEnthusiasm()).easyPrint()
}

выдает
Madrigal has left the building!
kotlin.Unit


Так что насчет «не компилируется» вы ошиблись.
> И внезапно оказалось, что эта оптимизация работает с конструктором и ломается, если заворачиваемое простое значение протаскивается через кэш внутри Integer::valueOf.

Факт!
В котлиновской стандартной библиотеке есть файл с кучей функций, которые нельзя вызвать извне стандартной библиотеки и они нигде не используются.
github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/src/kotlin/coroutines/jvm/internal/boxing.kt
Эти функции написаны как раз, чтобы заменить valueOf в корутиновом коде. В обычном коде боксинг удаляется компилятором, а в корутиновом приходится примитивы оборачивать. Поэтому компилятор заменяет все вызовы valueOf на вызовы Boxing.box[Type].
MORPHEUS: For the longest time, I wouldn't believe it. But then I saw the fields with my own eyes, watched them liquefy the dead so they could be fed intravenously to the living — NEO (politely): Excuse me, please.

MORPHEUS: Yes, Neo?

NEO: I've kept quiet for as long as I could, but I feel a certain need to speak up at this point. The human body is the most inefficient source of energy you could possibly imagine. The efficiency of a power plant at converting thermal energy into electricity decreases as you run the turbines at lower temperatures. If you had any sort of food humans could eat, it would be more efficient to burn it in a furnace than feed it to humans. And now you're telling me that their food is the bodies of the dead, fed to the living? Haven't you ever heard of the laws of thermodynamics?

MORPHEUS: Where did you hear about the laws of thermodynamics, Neo?

NEO: Anyone who's made it past one science class in high school ought to know about the laws of thermodynamics!

MORPHEUS: Where did you go to high school, Neo?

(Pause.)

NEO: ...in the Matrix.

MORPHEUS: The machines tell elegant lies.

(Pause.)

NEO (in a small voice): Could I please have a real physics textbook?

MORPHEUS: There is no such thing, Neo. The universe doesn't run on math.

www.hpmor.com/chapter/64
Тогда pi в этой системе счисления будет выглядеть как 10.
Да, вам одному так кажется. Ой, я имел в виду вам 1/е-му или вам 1/pi-му (выберите, какое число вам больше нравится) так кажется.

Information

Rating
Does not participate
Location
Долгопрудный, Москва и Московская обл., Россия
Date of birth
Registered
Activity