10. Многопоточность. Программирование на Rust (весна 2019).

แชร์
ฝัง
  • เผยแพร่เมื่อ 16 พ.ย. 2024

ความคิดเห็น • 35

  • @luckystrike91
    @luckystrike91 11 หลายเดือนก่อน +1

    мне очень помогло разобраться в атомиках и с memory order видео Crust of Rust: Atomics and Memory Ordering

  • @dmitry.aleksandrov
    @dmitry.aleksandrov 4 ปีที่แล้ว +4

    Спасибо за отличный курс! Но 1:30:29 в предпоследней строчке смените lock() на read() :)

    • @alekseykladov1144
      @alekseykladov1144 4 ปีที่แล้ว +3

      Ога, хорошаее замечание. На самом деле, можно ещё лучше -- позвать get_mut, который требует &mut RwLock и **не** захватывает сам лок. Те, мы тут статически понимаем, что у нас есть эксклюзивный доступ к мьютексу, и можем безопасно достать из него данные безо всякой синхронизации. Магия!
      doc.rust-lang.org/std/sync/struct.RwLock.html#method.get_mut

  • @deverloperfantom1372
    @deverloperfantom1372 5 ปีที่แล้ว +5

    Все четко говорит! Спасибо за информацию, лайк и подписка

  • @mascai
    @mascai ปีที่แล้ว +1

    39:23 В конце функции мейн не хватает handler.join().unwrap(); или я путаю?

  • @NikBond1000
    @NikBond1000 5 ปีที่แล้ว +15

    "Ваша программа - не программа"(с)

    • @wa7sa34cx
      @wa7sa34cx 3 ปีที่แล้ว +1

      Тоже понравилось 😆

  • @alexs7931
    @alexs7931 2 ปีที่แล้ว

    29:50 похоже на EventListener в js.
    30:26 Для s можно вызвать Builder, отлично!
    1:42:56 По поводу сырых указателей и move в mache.

  • @luna_moonspeak
    @luna_moonspeak 5 ปีที่แล้ว +2

    1:20:01 Должно быть "неважно, какой код вы _пишете_", а не "... _пишите_" ))

  • @lizzienovigot
    @lizzienovigot ปีที่แล้ว +2

    Блин долго я думал кого мне лектор напоминает... это же Фред и / или Джордж Уизли!
    Шалость удалась.

  • @Archidamus
    @Archidamus 5 ปีที่แล้ว

    21:58 Довольно необычно что можно вызывать mem::forget и этот будет ок. Получается на любые гварды, вроде Ref, RefMut из предыдущих лекций можно mem::forget и счетчик RefCell не вернется в нормальное состояние. Впрочем это должно вызвать каких-то проблем, раст как я понял считает что утечка - это ок (safe). Наверное у языка была возможность сделать mem::forget unsafe, как я понял он реализован через #[lang = "manually_drop"] - т.е. на уровне языка, а не каким-то safe кодом.

    • @KaraMaslyatam
      @KaraMaslyatam 5 ปีที่แล้ว

      Можно руками без unsafe утечь память через циклический список, про это будет дальше - th-cam.com/video/C-BpSwZOnNE/w-d-xo.html Используешь interior mutability контейнеры - сам себе злобный Буратино и нужно следить за циклическими структурами, быть готовым словить в рантайме панику или зависнуть в дедлоке.

  • @KirillLykov
    @KirillLykov 2 ปีที่แล้ว

    про существенно дороже атомарные операции -- на x86 atomic_add будет 60 циклов то есть в 15 раз как минимум дороже чем обычный

    • @luckystrike91
      @luckystrike91 4 หลายเดือนก่อน

      а какова стоимость системного вызова? если нужен атомарный инкремент, например, то прятать его за мъютексом это полная хрень. встречал подобный код в библиотеках

  • @KirillLykov
    @KirillLykov 2 ปีที่แล้ว

    И такой курс (про потоки синхронизацию модели памяти) есть -- th-cam.com/video/36LMjAFbFfg/w-d-xo.html
    Источник неоднозначности это не только компилятор но и неопределенный порядок исполнения инструкций процессором

  • @prigl4548
    @prigl4548 4 ปีที่แล้ว +2

    От меня ускользает понимание, зачем в API атомиков есть методы с memory order. Когда реально требуется memory order выше relaxed, гарантиями, которое это дает по happens-before, кажется, можно воспользоваться только в блоке unsafe. Т. е. в этом месте смешиваются API для «прикладного» и «системного» программирования. И для «прикладного» программирования без unsafe можно ошибочно указывать избыточный memory order просто от непонимания и потенциально ухудшить производительность на некоторых архитектурах. Как в примере со счетчиком в лекции, где sequential consistency для просто инкремента избыточно.

    • @alekseykladov1144
      @alekseykladov1144 3 ปีที่แล้ว +4

      Да, это верное наблюдение. В целом конечно можно придумать вырожденный пример на
      атомиках, где и без unsafe можно пронаблюдать memory orderings, но в реальном
      коде такого не возникает.
      Гипотетически, можно было бы придумать "простое" апи атомиков, где всё Relaxed,
      и сложное, с Ordering. Но тогда пришлось бы тащить два API. Тут ситуация похожа
      на сырые указатели, которы можно получать в safe code, но с которыми там ничего
      интересного не сделаешь.
      Отдельно согласен про инкремент. Я раньше придерживался популярной позиции, что
      надо по умолчанию делать SeqCst, и менять, только если бенчи показывают, что
      надо. Сейчас думаю, что это плохая стратегия, и что надо ставить минимально
      возможный Ordering, потому что так проще понять код. Иными словами, если ты не
      можешь объяснить, что код с `Relaxed` работает корректно, то ты тем более не
      сможешь объяснить, почему `SeqCst` работает. `SeqCst` добавит в теорему
      дополнительных, сложных и ненужных, условий, и сделает доказательство
      непонятнее.

  • @grachev330
    @grachev330 5 ปีที่แล้ว +3

    А в примере на 55:00 точно будет гонка?
    Мы же явно делаем join, счетчик на главном потоке будет увеличиваться до старта заспавненного потока, и уменьшаться уже после его завершения
    (drop Rc на главном потоке вызовется уже после join)

    • @KaraMaslyatam
      @KaraMaslyatam 5 ปีที่แล้ว

      Это так выглядит со стороны алгоритма. Компилятор может вообще не инкрементить счётчик (если мы не используем его значение явно) или инкрементить его после создания потока. Может быть как угодно, это UB. Если у потоков есть общая изменяемая память, необходимо использовать атомарные типы. Надо запомнить раз и навсегда: не будешь синхронизировать потоки - получишь UB (если пишешь unsafe Rust или С/C++ код).

    • @alekseykladov1144
      @alekseykladov1144 5 ปีที่แล้ว +1

      Кстати, да, действительно, тут гонки данных быть не должно, потому что join это точка синхронизации, спасибо! Привыка joinить треды помешала сделать правильный пример :-)
      Так что, в данном случае, компилятор запрешает этот код консервативно, но понятно что небольшая модификация (например, ещё один Rc::clone перед join) может легко привести к UB.

  • @yazvit
    @yazvit 4 ปีที่แล้ว +1

    Так данные пересекаются, кеш линии же есть - 4 инта вплотную друг к другу :) 41:00

    • @ihorrudynskyi466
      @ihorrudynskyi466 3 ปีที่แล้ว

      И что с того? Можно писать в 1 кеш линию с разных потоков хоть это и медленно из-за синхронизации. Код на слайде всегда напечатает единицы. на 44:00 лектор все обьясняет.

    • @stIncMale
      @stIncMale 2 ปีที่แล้ว

      Это называется false sharing, он может негативно влиять на производительность, но не на корректность.

  • @flashmozzg
    @flashmozzg 5 ปีที่แล้ว

    1:22:35 А как же системы, где нет 8-байтовых атомиков?

    • @KaraMaslyatam
      @KaraMaslyatam 5 ปีที่แล้ว +2

      Spinlock. Но это не про Rust, и даже не про LLVM (именно в таком случае как минимум на x86), а про выбор "сишной" реализации под каждую платформу. А вообще, меньше знаешь - крепче спишь.

    • @flashmozzg
      @flashmozzg 5 ปีที่แล้ว

      @@KaraMaslyatam Ну я к тому, что никаких доп. гарантий нет. По крайней мере по сравнению с C++. Поддерживается архитектурой - будет нативный атомик, иначе лок/мьютекс. Никакой магии.

    • @ПрограммистиКоммунист
      @ПрограммистиКоммунист 5 ปีที่แล้ว

      На таких системах не будут работать типы AtomicU64 и AtomicI64. Максимально переносимые типы - это AtomicUsize и AtomicIsize, но и они не будут работать на тех платформах, где атомики не поддерживаются вообще.

    • @flashmozzg
      @flashmozzg 5 ปีที่แล้ว

      @@ПрограммистиКоммунист Да, посмотрел в доку. Там системах, где не поддерживаться просто не будут определены типы.

  • @sergeysergeev1132
    @sergeysergeev1132 ปีที่แล้ว +2

    Все классно, но эти эканья и причмокивания каждые 3 секунды просто пытка(

  • @KaraMaslyatam
    @KaraMaslyatam 5 ปีที่แล้ว

    Зачем ".rodata" секции права на исполнение? Ведь Rust знает, что эти данные не надо исполнять. А любителям непортабельного unsafe кода можно дать какой-нибудь аттрибут типа #[derive(ExecutableAndVeryUnsafe)] и мержить это добро в ".text". А так никакого смысла в отдельной секции нет и вроде как где-то всё мержится в ".text" (логично).

    • @KaraMaslyatam
      @KaraMaslyatam 5 ปีที่แล้ว

      Понятно. Это оптимизация линковщиков, которым плевать, что ты там хочешь отдельный "R--" сегмент памяти, схаваешь и "R-X" - нечего отнимать драгоценные дескрипторы и делать лишний вызов. Расчёт на то, что в рид-онли секции исполняемого файла не может быть ничего настолько исполняемого, чтобы сделать что-то плохое (жуткое заблуждение).

    • @flashmozzg
      @flashmozzg 5 ปีที่แล้ว +1

      Все эти .rodata, .text и т.д., это уже не к Rust-у вопросы, а к ОС/ABI. Это к тому, что "Ведь Rust знает, что эти данные не надо исполнять". - знать то он знает, но на то, как в target системе реализованы exe-шники он повлиять не может.