Здравствуйте, WolfHound, Вы писали:
WH>>>Вполне конкретное признание того что SObjectizer от проблем не защищает. _>>Конечно. Только от таких проблем не защищает никто. WH>Rust, pony, erlang,...
Rust здесь лишний. В erlang-е вы в принципе не сможете передать ссылку на разделяемые мутабельные данные. А в Rust-е сможете. И компилятор вам сможет помочь в проверке наличия safe-интерфейса (как вы это называете). Но вот проверить то, что находится под этим safe-интерфейсом компилятор, из-за наличия в языке unsafe не сможет.
А это говорит о том, что обеспечение гарантий, которые, по вашим словам, предоставляет Rust, происходит за счет организационных мероприятий: мол, мы дадим право писать unsafe-код только обладателям малиновых штанов. И поэтому у нас все будет безопасно.
Вот только обеспечение гарантий за счет процесса разработки и обеспечение гарантий за счет системы типов и других языковых особенностий -- это несколько разные вещи.
Здравствуйте, so5team, Вы писали:
S>Вот только обеспечение гарантий за счет процесса разработки и обеспечение гарантий за счет системы типов и других языковых особенностий -- это несколько разные вещи.
1)Называть запрет одного ключевого слова процессом разработки это натягивание совы на глобус.
2)В случае со всеми языками мы должны доверять компилятору и стандартной библиотеке. Ибо внутри там тоже один сплошной unsafe. Да и любой интероп это тоже unsafe.
И если нам очень надо, то мы можем сделать свою библиотеку имеющую safe интерфейс. Но по необходимости делающую внутри что-то unsafe.
В то же время на С++ ты не сможешь сделать safe интерфейс не важно как ты будешь извращаться.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, so5team, Вы писали:
S>>>В D есть invariant. WH>>Как он может помочь?
S>Обеспечивает реальную иммутабельность. Причем транзитивную. Нет проблем передавать в сообщениях invariant-ссылки, да и сами сообщения могут быть invariant-объектами. И не будет у вас разделяемых данных.
Поправка: это immutable.
Слово invariant в D тоже есть, но означает совсем другое — из области контрактов.
Здравствуйте, WolfHound, Вы писали:
WH>1)Называть запрет одного ключевого слова процессом разработки это натягивание совы на глобус.
Если вы проекте разрешаете кому угодно писать unsafe в коде, то разговоры про гарантии компилятора могут продолжать только рьяные фанбои.
Если вы в проекте раздаете права на использование unsafe, то да, вы именно что разруливаете технические проблемы организационными средствами.
WH>2)В случае со всеми языками мы должны доверять компилятору и стандартной библиотеке. Ибо внутри там тоже один сплошной unsafe. Да и любой интероп это тоже unsafe.
Если вы перестанете продвигать Rust так же рьяно, как, судя по рассказам, вы продвигали Nemerle, и сможете прочитать то, что вам пишут, то увидите, что речь идет не о доверии к компилятору или стандартной библиотеке.
Речь идет о том, что в модели акторов акторы имеют собственное состояние, которое никому больше не доступно. Нарушить это можно, если передавать в сообщениях ссылки на мутабельные разделяемые данные. И в Rust-е, и в C++ это можно сделать (тогда как в Erlang-е в принципе нельзя).
При этом в C++ вообще нет никакого серьезного контроля за тем, что передается в сообщениях (хоть голый указатель, хоть умный, хоть экземпляр класса, у которого это все где-то глубоко в потрохах). С этим никто не спорит.
Но вот про Rust вы говорите, что в Rust-е есть гарантии.
Хотя на самом деле полноценных гарантий, как в Erlang-е, нет. Т.е. вы можете передать объект, который имеет safe-интерфейс снаружи и кучу unsafe внутри. И гарантии компилятора здесь оказываются на уровне "мамой клянусь" от разработчика, который эти unsafe написал. При этом речь идет не о коде компилятора или системной библиотеке. А о коде, который обычный разработчик будет писать для решения своей прикладной задачи.
WH>В то же время на С++ ты не сможешь сделать safe интерфейс не важно как ты будешь извращаться.
Не смогу. Но отсутствие гарантий в C++ не является доказательством наличия гарантий в Rust-е.
Здравствуйте, WolfHound, Вы писали:
_>>А для того, чтобы получить проблемы с многопоточностью совсем не обязательно получать доступ к памяти мимо мьютекса. Более того, как раз мьютексы и вызывают довольно большую часть проблем (например https://users.rust-lang.org/t/using-rayon-in-code-locked-by-a-mutex/20119 — ты помнится прямо эту библиотечку тут хвалил?) в многопоточном коде. Так что твои смешные идеи в стиле "просто поменяем последовательный запуск кода на параллельный и компилятор отследит все некорректности" — это очевидно фантастика. WH>1)Показать доступ к памяти без надлежащей синхронизации ты не можешь.
Вообще то как раз показал, в одном из начальных сообщений. Причём что самое интересное (особенность именно Rust, т.к. в нём взятие даже небезопасной ссылки не требует unsafe): unsafe блок там может располагаться вообще в другом модуле кода, а в коде самого потока никакого unsafe нет.
WH>2)Устроить дедлок можно почти на чём угодно. Например, если актор может синхронно обратиться к другому актору, жди дедлоков. А если ты реализовал акров на пуле потоков, то дедлоки тебя найдут ещё быстрее.
Синхронно обратиться — это как? Случаем не через тот же самый мьютекс?
WH>3)Отлаживать дедлоки гораздо проще, чем гонки. Ибо в случае с дедлоком видно кто на ком висит. А в случае с гонками программа иногда разлетается на куски и кто виноват совершенно не ясно.
Одинаково трудно отлаживается. Причём основная проблема в том, что очень трудно покрыть отладкой все возможные сценарии некорректного многопоточного кода.
WH>4)По той ссылке написано как можно решить эту проблему на уровне библиотеки, не меняя пользовательский код.
Так же как и в любом другом языке, за редкими исключениями (типа Erlang). И Rust к этим исключениям точно не относится — он не даёт никаких гарантий корректной многопоточности, как ты сам видишь по самому факту наличия этой ошибки. Понятно что её можно исправить (как и в любом другом языке), но если бы были гарантии корректности, то компилятор просто не позволил бы такой код.
WH>5)Нормальные люди ничего тяжёлого под мьтексом не делают. Так что тут чувак намеренно проблемы искал.
Хаха, вот явно ты вообще не в курсе этой области программирования. Как раз под мьютексами тяжёлое и делают. Потому как и сами мьютексы совсем не лёгкие (работают через ядро ОС). А если требуется именно быстрый лёгкий код, то применяют различные виды atomic'ов и т.п. CAS'ы.
_>>Не "Питон это делает", а такое можно сделать на Питоне. И я вполне подробно описывал как в сообщениях выше — просто модифицируем код (грубо говоря вешаем декораторы на всех его членов, плюс добавляем пару новых методов типа lock/unlock) того объекта , доступ к которому надо защитить мьютексом. Естественно это не программист руками будет делать, а всё произойдёт автоматически при подключение защиты к данному объекту — у динамических языков есть свои преимущества. WH>1)Это можно делать на любых языках с метарограммированием. Динамическая типизация тут не нужна. Да и руками написать такое не сложно. WH>2)Никогда не видел, чтобы так делали.
Ну давай, расскажи как например на том же Rust'е (в нём же есть метапрограммирование) изменить поведение конкретного экземляра данного типа, не модифицируя сам тип.
WH>>>Особенно интересует пример, в котором объекты под мьютексом живут разное время. _>>Ну вот тебе компилируемый пример на C++ с защитой набора разделяемых данных мьютексом: WH>Мне не нужен кусок говнокода, который ничего не делает. WH>Мне нужна реальная задача, при решении которой такое нужно.
Понятно. Ожидаемый слив. )))
WH>Защитники динамической типизации тоже любят показывать несколько строк говнокода, который невозможно один в один повторить на большинстве статически типизированных языков. WH>Но когда у них спрашиваешь про задачу, которую они этим кодом собрались решать сливаются в 100%ах случаев.
Да, только я привёл пример не на динамическом языке, а на вполне себе статическом C++, который Rust в теории должен заменять.
_>>Ну и кстати говоря у Rust'а точно такая же реализация, только там контейнер и мьютекс изначально объединены в одну сущность. WH>Так я и не понял реализация в rust плохая, ибо не позволяет написать код, который ты привёл выше или хорошая по тому, что так и нужно делать. Плюс у rust'а все проверки на этапе компиляции.
Реализация мьютекса в Rust (с контролем доступа к некому объекту) просто не нужная. Но если вдруг есть желание повторить её именно такой, то это легко делается на всех языках (при наличие доступа к классическому мьютексу).
Здравствуйте, WolfHound, Вы писали:
_>>Это как раз стандартная трактовка. Причём что самое интересное, даже если мы будем говорить например о реализации зелёных потоков в рамках одного системного (скажем сопрограммы в C++ или async/await в C# в рамках GUI потока), то применение модели акторов позволяет убрать проблемы гонок и здесь. Как раз потому, что модель акторов формулируется не в терминах системных потоков. WH>Но и у rust'а тут не будет никаких проблем.
Конечно. Я нигде и не говорил, что Rust чем-то хуже других системных языков в области многопоточности. Я всего лишь опровергал известный миф о том, что он чем-то лучше.
_>>Потоки то тоже разные бывают... ) Ну да ладно, даже если мы ограничимся только системными потоками, то даже тут автоматическая расстановка мьютексов абсолютно не гарантирует корректности получаемого кода. Даже скорее наоборот, без умения применять этот инструмент, есть солидные шансы получить взаимные блокировки. WH>Взаимные блокировки можно получить на чём угодно. Я видел распределённые взаимные блокировки на пуле потоков.
Ну вот расскажи как получить взаимные блокировки например при полном следование модели акторов...
_>>В C++ память в большинстве случаев управляется автоматически. Ручное управление обычно требуется при взаимодействие с чужим кодом (C библиотеки, OS API и т.п.) или чем-то совсем низкоуровневым (драйверы, микроконтроллеры). Точно так же как и в Rust'е, в котором все библиотеки (включая стандартную), работающие с внешним API, насквозь пропитаны unsafe. WH>Внутри пропитаны. Это ключевое. WH>А снаружи у них safe интерфейс. И при использовании про память думать уже не нужно. WH>Разработчик обёртки уже за нас подумал. WH>А в С/С++ библиотеки с небезопасным интерфейсом обычное дело. WH>Я даже использовал библиотеку для работы, с которой было необходимо использовать setjump/longjump. WH>В случае с rust найти библиотеку с небезопасным интерфейсом не просто.
Я думаю ты должен понимать, что такая ситуация с библиотеками является следствием не разного дизайна языков, а их разного исторического пути.
_>>Да, и я вот не пойму чего ты всё время переключаешься на C++, хотя мы тут обсуждаем Rust? У тебя болит C++? ))) WH>Так rust это замена для С/С++. С чем же его ещё сравнивать?
Насчёт замены ты конечно прав. Только вот вместо попыток найти какие-то минусы у C++ (смешно на самом деле, т.к. их множество и при этом они давно всем известны), ты бы лучше продемонстрировал бы какие-то плюсы Rust.
_>>Ну ОК, но это же и для других языков тогда тоже должно работать не так ли? Чтобы не было двойных стандартов... Т.е. вполне нормально рассматривать какое-то административно ограниченное подмножество любого языка, правильно? ) WH>Запрет одного ключевого слова и здоровенный талмуд, описывающий что можно и что нельзя сильно разные вещи.
Согласен. У Rust'а есть определённые преимущества. Правда за них приходится расплачиваться написанием некоторого лишнего синтаксического шума.
И да, это относится только к управлению памятью. А например в той же многопоточности здоровенный талмуд будет и в C++ и в Rust...
WH>>>"если следовать модели мьютексов (это предусловие, не важно как достигаемое!), то это устранит все классические проблемы многопоточности (результат)" WH>>> _>>Вот в том то и дело, что не устранит, а скорее всего только их умножит. Ты сейчас хорошо показал, что вообще не в теме проблемы. WH>Ты уверен, что я? Если я правильно использую мьтексы то, какие могут возникнуть проблемы? Я же их использую правильно.
Конечно. И это полностью аналогично утверждению о том, что на голом C с его указателями можно написать быстродействующую и абсолютно корректную программу. Естественно при высоком уровне профессионализма и внимательном отношение к коду. Только вот народ что-то предпочитает переходить к автоматическому управлению типа C++/Rust...
К сожалению в области многопоточности нет аналога автоматического управления памятью C++/Rust. Всё же немногие существующие автоматические решения в этой области (типа реализации модели акторов в Эрланге) позволяют это делать ценой потери производительности — т.е. они в каком-то смысле являются аналогами решений по памяти со сборщиками мусора.
_>>Что ты всегда говорил? Ты начал спорить с моим конкретным утверждением о свойстве модели акторов. WH>Я начал говорить о том, что большинство языком эти свойства не гарантируют.
Свойства модели акторов гарантируются математикой, а не языками программирования. Ознакомься с теорией что ли... )))
_>>Хы, интересно как ты себе вообще представляешь гарантию языком следования модели акторов? WH>Erlang и pony построены вокруг акторов.
Про pony ничего не знаю — никогда не слышал про такой язык. А вот Erlang — это да, одно из немногих исключений. И поэтому он является не универсальным языком, а весьма нишевым.
_>>Потому как например тоже самое использование разделяемых данных (пускай и защищённых мьютексом), уже является нарушением и при этом доступно в большинстве языков (включая Rust). Следование данной модели — это исключительно самоограничение программиста и всё. Никаких гарантий от компилятора ты тут добиться не сможешь (ну если конечно не брать язык, в котором модель акторов — это единственный доступный способ взаимодействия между задачами). WH>В случае с rust имеем. Причем в случае с evmap гарантированно проблем не будет.
И опять же ты ничего не понимаешь в этой теме. Локфри контейнер — это всего лишь продвинутая разновидность atomic'а, которая не гарантирует корректную работу многопоточного кода. Единственное, что гарантируют такие контейнеры (как и любые atomic'и), это отсутствие наложения параллельных действий. Однако это не гарантирует корректности, потому как например тоже самое отсутствие наложения, может приводить к потерям части действий и т.п.
Вот модель акторов (в отличие от любых видом разделяемых данных, включая локфри) даёт тебе гарантии корректности. Но если ты притащишь в неё такую штуку, то гарантии эти тут же потеряешь. Это не значит, что ты сразу получишь неверно работающий код — профессионал во многих случаях сможет корректно решить задачу, но это будет уже исключительно его личное достижение (так же как при управление голыми указателями в коде на C), а не гарантии архитектуры.
WH>>>Вполне конкретное признание того что SObjectizer от проблем не защищает. _>>Конечно. Только от таких проблем не защищает никто. WH>Rust, pony, erlang,...
Про pony ничего не знаю. Erlang — это да, специфический нишевый язык. Rust — нет, не защищает.
_>>Гарантии корректности многопоточности — это значит, что если ты делаешь всё правильно (да, да, внимательно следишь за своими руками), то получишь корректную многопоточную работу. WH>Если ты делаешь всё правильно то у тебя и на С код отлично работать будет. Вот только обычно не работает.
Так, похоже ты никак не можешь понять простой ключевой момент в использование модели акторов. Давай попробую тебе объяснить. Смотри:
у нас есть изначальная задача — добиться корректного многопоточного кода
это задача сам по себе очень сложная, т.к. для гарантированной корректности надо просмотреть слишком много вариантов развития событий
более того, до сих пор нет формализованного алгоритма (пускай даже и очень сложного) для решения этой задачи напрямую
модель акторов позволяет гарантировать корректность многопочности, при следование определённым очень простым условиям
таким образом, применяя модель акторов, мы получаем замену сложнейшей задачи на очень простую (которую элементарно можно отследить в коде приложения).
Но естественно это всё не бесплатно — есть определённые потери в производительности при применение этой модели, потому как для некоторых задач однозначно наиболее эффективны разделяемые данные, а модель акторов их запрещает. Возможно поэтому данный подход не царит повсеместно. Например у меня в задаче с реалтаймым видео не было никаких акторов, а был общий кусок памяти (текущий кадр), с которыми одновременно работало несколько потоков (выполняя разные стадии преобразования). Правда синхронизировались они не медленными мьютексами, а быстрыми atomic'ами. Но ценой идеального быстродействия тут была потребность очень очень внимательно работать с этим куском кода.
_>>Т.е. естественно и Rust и другие языки позволяют использовать и модель акторов и разделяемые мутабельные данные. Но если ты попробуешь смешать это, то в большинстве случаев получишь нарушение всех гарантий. WH>В rust не получишь. WH>Ты, конечно, можешь попробовать продемонстрировать, как evmap нарушает гарантии акторов. Вот только что-то мне говорит, что кода как обычно не будет.
Думаю там без проблем можно получить некорректное приложение. Оно не будет зависать, но зато будет иногда выводить некорректные данные. Потому как lock-free вполне позволяет такое при неаккуратном использование.
WH>>>А твои претензии к Option вообще абсурдны. Nullable типов вообще быть не должно. Они сами по себе большая проблема. _>>Что за мои претензии к Option? Это ты откуда вообще такое взял? ))) WH>Ты же на вот этот тип возбудился Option<Box<Data>> WH>Причём я у тебя долго спрашивал, что за проблемы с типами в rust. WH>Ты молчал как рыба об лёд. Видимо понимал, что за такую ерунду засмеют.
Аааа, вот ты про что. Я если честно даже и не читал какие конкретно контейнеры вписал там Иван. Я среагировал просто на тройную (это кстати для Rust'а ещё не сильно много) вложенность типов, а не на сами типы. )))
_>>Вообще говоря на этом форуме особо и развенчивать не надо, т.к. большинство в курсе реальности — всё же уже много лет назад обсудили все особенности Rust. Иногда вот только возникают восторженные фанаты, которые прочитали в какой-то компьютерной жёлтой прессе, что Rust помогает не только воспитать правильный подход к управлению памятью (через владение), но и решает проблемы многопоточности. Тогда приходится им пояснять, что это просто слухи... WH>В отличие от тебя я изучаю языки, начиная с высокоуровневых концепций и заканчивая низкоуровневой реализацией. WH>Rust действительно даёт гарантии, о которых я говорю. WH>Твои постоянные апелляции к unsafe говорят о том, что ты это понимаешь, но очень хочешь поспорить.
Гарантии отсутствия доступа к защищённому мьютексом объекту он действительно даёт (правда и то только при наличие административного запрета на использование unsafe по всему проекту). Только вот никакого отношения к гарантиям корректной многопоточности это не имеет. А только это и интересно на практике.
Здравствуйте, alex_public, Вы писали:
WH>>Мне не нужен кусок говнокода, который ничего не делает. WH>>Мне нужна реальная задача, при решении которой такое нужно.
_>Понятно. Ожидаемый слив. )))
В написанном виде этот код -- unsound, и Rust просто не даст его написать, borrow checker ругаться будет. Там возможна висящая ссылка.
Здравствуйте, so5team, Вы писали:
S>Если вы проекте разрешаете кому угодно писать unsafe в коде, то разговоры про гарантии компилятора могут продолжать только рьяные фанбои.
S>Если вы в проекте раздаете права на использование unsafe, то да, вы именно что разруливаете технические проблемы организационными средствами.
Пока что даже здесь приводят примеры того, что для решения серьезных задач на Rust-е приходится прибегать к unsafe. А раз есть unsafe, то про гарантии языка говорить не приходится. Если, конечно, говорить спокойно, а не пытаться фанбоить.
Так что еще раз, чтобы было понятнее: речь не о том, что Rust плох, что он небезопасен так же, как и C++. И уж тем более речь не о том, что C++ позволяет программировать так же безопасно, как Rust.
Речь идет о том, что "у Rust-е есть гарантии" -- это выдача желаемого за действительное.
Программировать на Rust-е безопаснее, чем на C++, но гарантий нет. Если вы решили отстрелить себе ногу, вам никто не помешает это сделать. Из-за наличия того самого unsafe.
Здравствуйте, alex_public, Вы писали:
_>Вообще то как раз показал, в одном из начальных сообщений. Причём что самое интересное (особенность именно Rust, т.к. в нём взятие даже небезопасной ссылки не требует unsafe): unsafe блок там может располагаться вообще в другом модуле кода, а в коде самого потока никакого unsafe нет.
То есть без unsafe не можешь.
WH>>2)Устроить дедлок можно почти на чём угодно. Например, если актор может синхронно обратиться к другому актору, жди дедлоков. А если ты реализовал акров на пуле потоков, то дедлоки тебя найдут ещё быстрее. _>Синхронно обратиться — это как? Случаем не через тот же самый мьютекс?
Послать сообщение и подождать ответ.
_>Одинаково трудно отлаживается. Причём основная проблема в том, что очень трудно покрыть отладкой все возможные сценарии некорректного многопоточного кода.
Ты вообще хоть раз многопоточный код отлаживал?
Ловля гонок это исключительно внимательное чтение кода.
А если у тебя программа нарвалась на дедлок, то просто цепляешься отладчиком и дедлок как на ладони.
_>Так же как и в любом другом языке, за редкими исключениями (типа Erlang). И Rust к этим исключениям точно не относится — он не даёт никаких гарантий корректной многопоточности, как ты сам видишь по самому факту наличия этой ошибки. Понятно что её можно исправить (как и в любом другом языке), но если бы были гарантии корректности, то компилятор просто не позволил бы такой код.
Ещё раз. Данный код корректен. Нужно просто доработать библиотеку.
_>Хаха, вот явно ты вообще не в курсе этой области программирования. Как раз под мьютексами тяжёлое и делают. Потому как и сами мьютексы совсем не лёгкие (работают через ядро ОС). А если требуется именно быстрый лёгкий код, то применяют различные виды atomic'ов и т.п. CAS'ы.
Мьютексы они разные бывают. Вполне возможна реализация, работающая без обращения к ядру ОС.
В данном случае я про их реализацию вообще ничего не говорил.
Только про модель использования.
_>Ну давай, расскажи как например на том же Rust'е (в нём же есть метапрограммирование) изменить поведение конкретного экземляра данного типа, не модифицируя сам тип.
А зачем такое нужно?
WH>>Мне не нужен кусок говнокода, который ничего не делает. WH>>Мне нужна реальная задача, при решении которой такое нужно. _>Понятно. Ожидаемый слив. )))
С твоей стороны однозначный слив.
Придумать такой говнокод и я могу.
Вот чего я не могу, это придумать реальную задачу где такое нужно.
WH>>Защитники динамической типизации тоже любят показывать несколько строк говнокода, который невозможно один в один повторить на большинстве статически типизированных языков. WH>>Но когда у них спрашиваешь про задачу, которую они этим кодом собрались решать сливаются в 100%ах случаев. _>Да, только я привёл пример не на динамическом языке, а на вполне себе статическом C++, который Rust в теории должен заменять.
Ты даже не понял, что я написал.
Перечитай раз 10. Может до тебя дойдет, что я привёл иллюстрацию твоего слива.
_>Реализация мьютекса в Rust (с контролем доступа к некому объекту) просто не нужная.
Ты не показал ни одного реального примера, где нужен другой сценарий.
_>Но если вдруг есть желание повторить её именно такой, то это легко делается на всех языках (при наличие доступа к классическому мьютексу).
Только гарантий времени компиляции ты не получишь.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, alex_public, Вы писали:
_>Конечно. Я нигде и не говорил, что Rust чем-то хуже других системных языков в области многопоточности. Я всего лишь опровергал известный миф о том, что он чем-то лучше.
Он намного лучше. В других языках весь код без исключения unsafe. А на rust весь код safe.
unsafe нужен очень редко для создания чего-то хитроумного.
Многие программы вообще можно написать, не используя unsafe.
_>Ну вот расскажи как получить взаимные блокировки например при полном следование модели акторов...
А моделей акторов в реальной жизни до чёртиков.
Сколько реализаций столько и моделей.
Если реализация позволяет актору ждать конкретное сообщение, то дедлоки за тобой уже выехали.
_>Я думаю ты должен понимать, что такая ситуация с библиотеками является следствием не разного дизайна языков, а их разного исторического пути.
Тут именно разный дизайн языка.
В случае с rust легко делать safe библиотеки. Более того все ожидают что у библиотеки будет safe интерфейс.
А в случае с C/C++ всё держится на соглашениях.
_>Насчёт замены ты конечно прав. Только вот вместо попыток найти какие-то минусы у C++ (смешно на самом деле, т.к. их множество и при этом они давно всем известны), ты бы лучше продемонстрировал бы какие-то плюсы Rust.
Так я и демонстрирую. Просто ты заткнул уши и кричишь unsafe, unsafe, unsafe, unsafe,...
Причём совершенно не ясно, зачем ты это делаешь.
_>Согласен. У Rust'а есть определённые преимущества. Правда за них приходится расплачиваться написанием некоторого лишнего синтаксического шума.
Ты его так ни разу и не продемонстрировал. А я тебя уже раз 10 просил.
Ну что слив засчитываем?
_>И да, это относится только к управлению памятью. А например в той же многопоточности здоровенный талмуд будет и в C++ и в Rust...
В rust не будет.
WH>>Ты уверен, что я? Если я правильно использую мьтексы то, какие могут возникнуть проблемы? Я же их использую правильно. _>Конечно. И это полностью аналогично утверждению о том, что на голом C с его указателями можно написать быстродействующую и абсолютно корректную программу. Естественно при высоком уровне профессионализма и внимательном отношение к коду. Только вот народ что-то предпочитает переходить к автоматическому управлению типа C++/Rust...
Тебе осталось сделать ещё один шаг и понять, что к акторам это тоже относится.
_>К сожалению в области многопоточности нет аналога автоматического управления памятью C++/Rust. Всё же немногие существующие автоматические решения в этой области (типа реализации модели акторов в Эрланге) позволяют это делать ценой потери производительности — т.е. они в каком-то смысле являются аналогами решений по памяти со сборщиками мусора.
Вот только в случае с ерлангом есть вполне известные проблемы.
Например, из-за наличия selective receive получение сообщения из очереди O(N).
И если вдруг в очереди окажется слишком много сообщений, то ерланг начинает тупить на разборе этой очереди. И отзывчивость системы сразу падает до нуля.
От дедлока мало чем отличается.
Всё что нужно для того чтобы это спровоцировать кратковременный всплеск нагрузки.
WH>>Я начал говорить о том, что большинство языком эти свойства не гарантируют. _>Свойства модели акторов гарантируются математикой, а не языками программирования. Ознакомься с теорией что ли... )))
А реализуются они математикой или конкретным языком программирования?
WH>>В случае с rust имеем. Причем в случае с evmap гарантированно проблем не будет. _>И опять же ты ничего не понимаешь в этой теме. Локфри контейнер — это всего лишь продвинутая разновидность atomic'а, которая не гарантирует корректную работу многопоточного кода. Единственное, что гарантируют такие контейнеры (как и любые atomic'и), это отсутствие наложения параллельных действий. Однако это не гарантирует корректности, потому как например тоже самое отсутствие наложения, может приводить к потерям части действий и т.п.
Ты даже не ознакомился с тем, что такое evmap, а мнение имеешь.
У evmap чтение транзакционное.
Все изменения живут внутри write handle, который существует в одном экземпляре. Изменения становятся доступны на чтение только после вызова refresh(). При этом потоки которые начали читать до refresh, будут продолжать читать старую версию данных. Потоки, которые начнут читать после refresh, увидят все изменения.
Короче уровень изоляции serializable без оговорок.
WH>>>>Вполне конкретное признание того что SObjectizer от проблем не защищает. _>>>Конечно. Только от таких проблем не защищает никто. WH>>Rust, pony, erlang,... _>Про pony ничего не знаю. Erlang — это да, специфический нишевый язык. Rust — нет, не защищает.
Делаем на rust реализация акторов и вперёд с песней. Rust позволяет сделать safe интерфейс. Гарантии будут не хуже чем у ерланга.
Про unsafe петь не надо. Ибо я тогда начну про интероп. Думаю, ты и сам понимаешь, что интероп все гарантии ерланга отправляет куда подальше.
_>таким образом, применяя модель акторов, мы получаем замену сложнейшей задачи на очень простую (которую элементарно можно отследить в коде приложения).
Только в твоих мечтах.
Особенно если на С++.
_>Думаю там без проблем можно получить некорректное приложение. Оно не будет зависать, но зато будет иногда выводить некорректные данные. Потому как lock-free вполне позволяет такое при неаккуратном использование.
Код в студию.
Ничего у тебя с evmap не выйдет.
Единственная возможность сломать evmap, это сделать refresh внутри транзакции чтения.
Учитывая то, что у evmap только один write handle сделать это, мягко говоря, не просто.
_>Аааа, вот ты про что. Я если честно даже и не читал какие конкретно контейнеры вписал там Иван. Я среагировал просто на тройную (это кстати для Rust'а ещё не сильно много) вложенность типов, а не на сами типы. )))
Так в С++ будет то же самое если использовать умные указатели и опциональные типы.
Короче лицемерие на марше.
_>Гарантии отсутствия доступа к защищённому мьютексом объекту он действительно даёт (правда и то только при наличие административного запрета на использование unsafe по всему проекту). Только вот никакого отношения к гарантиям корректной многопоточности это не имеет. А только это и интересно на практике.
На практике дедлок очень простая и скучная проблема. Первый и последний дедлок у меня был около 20ти лет назад. Отладка заняла несколько минут. Просто посмотрел содержимое стеков потоков и всё стало ясно. Ещё минут 30 заняло исправление.
А вот доступ к памяти без синхронизации задача очень сложная и весёлая. Ибо все, что тебе известно это то, что продакшен разлетается на куски раз в месяц. В дампе полная каша, из которой ничего понять нельзя. Вот и думай, что это было. Гонки, выход за приделы массива, использование освобождённой памяти,...
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, alex_public, Вы писали:
_>Ну вот расскажи как получить взаимные блокировки например при полном следование модели акторов...
Если два актора решат ждать сообщение друг от друга — будет типичный deadlock. Вот тут пример на эрланге: http://james-iry.blogspot.com/2009/04/erlang-style-actors-are-all-about_16.html
Ещё могут быть live locks и туча других проблем многопоточности.
_>Я думаю ты должен понимать, что такая ситуация с библиотеками является следствием не разного дизайна языков, а их разного исторического пути.
Можешь показать хоть один более менее крупный проект C++ с безопасным кодом? Для rust такое есть. А пока получается как "на С++ можно писать безопасно, но мы не хотим", прям классика "я всегда могу бросить".
_>К сожалению в области многопоточности нет аналога автоматического управления памятью C++/Rust. Всё же немногие существующие автоматические решения в этой области (типа реализации модели акторов в Эрланге) позволяют это делать ценой потери производительности — т.е. они в каком-то смысле являются аналогами решений по памяти со сборщиками мусора.
Ты просто всё свалил в одну кучу. Вот и получилась чушь. Сборщики мусора не решают "[все] проблемы управления памятью", а вполне определённые, например, обращение к освобождённой или неинициализированной памяти, висящие объекты. Но не решают проблемы утечек памяти, например. Так и Rust не решает "[все] проблемы многопоточности", а позволяет защититься от вполне определённых проблем, например, data race. C++ не позволяет. Нужно ли это? Конечно, ибо data race довольно частая и труднообнаружимая проблема, и её решение значительно упрощает написание кода. Ровно так же и сборщики мусора — решают наиболее частую и вредную проблему.
По поводу использования unsafe vs "правильный С++" — это опять словоблудие. Вот пришел тебе пулл реквест на review — в случае rust ты можешь сразу увидеть unsafe и насторожиться. Можно даже тулзы соответсвтвующим настроить, чтобы коммиты с unsafe реджектить или назначать более серьёзный review всей командой. В случае С++ любое изменение потенциально может поломать всё что угодно и нет никакого простого и однозначного способа отличить безопасные изменения от опасных.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, so5team, Вы писали:
S>Программировать на Rust-е безопаснее, чем на C++, но гарантий нет. Если вы решили отстрелить себе ногу, вам никто не помешает это сделать. Из-за наличия того самого unsafe.
С такой позицией, любой язык, где есть FFI автоматически переходит в эту категорию.
А с практической точки зрения, если не "фанбоить" на "абсолютные" гарантии, у нас на ~200 тыс. строк кода, unsafe, помимо FFI (где всё плохо по очевидным причинам), в 5 местах, всего 9 ключевых слов "unsafe". Это те 5 мест, которые нужно один раз внимательно просмотреть, а дальше компилятор уже сам. При этом большая часть наших инженеров пишущих на Rust (~12), этот Rust видит первый раз в жизни.
За всё время мы ни разу не столкнулись с отладкой висящий ссылок, use-after-free, memory data race, ну, по крайней мере, мне эти случаи неизвестны За полтора года один раз был один случай повреждения памяти, оказалась ошибка оптимизатора в LLVM. Это к слову о "гарантиях".
Любая система в конце-концов всё равно будет базироваться на более низкоуровневых блоках, в которых возможно разное (в том числе, и потому что они написаны на C). libc, ядро Linux, и так далее. С этой позиции "unsafe Rust" -- будут те самые низкоуровневые блоки.
Здравствуйте, Иван Дубров, Вы писали:
S>>Программировать на Rust-е безопаснее, чем на C++, но гарантий нет. Если вы решили отстрелить себе ногу, вам никто не помешает это сделать. Из-за наличия того самого unsafe.
ИД>С такой позицией, любой язык, где есть FFI автоматически переходит в эту категорию.
Нет. FFI -- это выход за пределы возможностей языка. Так что еще раз, поскольку почему-то до торговцев Rust-ом не доходит: Erlang позволяет не выходить за пределы языка и иметь гарантии. Rust позволяет оставаться в пределах языка и при этом класть большой болт на какие-либо гарантии.
Поэтому в Erlang-е гарантии есть, в Rust-е нет.
И еще раз для тех, кому эта позиция кажется наездом на богом данный им Rust: отсутствие гарантий в Rust-е не делает его хуже.
ИД>За всё время мы ни разу не столкнулись с отладкой висящий ссылок, use-after-free, memory data race, ну, по крайней мере, мне эти случаи неизвестны За полтора года один раз был один случай повреждения памяти, оказалась ошибка оптимизатора в LLVM. Это к слову о "гарантиях".
Поскольку тут упоминался SObjectizer как пример для небезопасного C++, то за 17 лет его применения вот этих всех прелестей разработчики при использовании SObjectizer-овских агентов и SObjectizer-овских сообщений не испытывали. Хотя, казалось бы, небезопасный C++, ой-ой-ой и ай-ай-ай, никаких гарантий даже в принципе.
ИД>С этой позиции "unsafe Rust" -- будут те самые низкоуровневые блоки.
Еще раз: речь не о блоках, от которых никуда не деться (ОС, компилятор, стандартная библиотека). Речь о том, что при написании прикладного кода никто не запрещает разработчику задействовать unsafe. Т.е. разработчики никуда не выходит из языка, не опускается в FFI, но "гарантии" идут в пешее эротическое.
Так что если бы вы и WolfHound говорили о том, что Rust безопаснее и C++ и многих других языков, что Rust бьет по рукам разработчика при попытках использовать небезопасные конструкции, то предмета для спора не было бы. Но ведь вам важно накормить всей собственной верой в наличие именно гарантий.
Здравствуйте, Иван Дубров, Вы писали:
_>>Ну открой код Rust'а и посмотри — просто контейнер, агрегирующий некий объект и возвращающий ссылку на него по функции Lock, в случае языков без RAII. А в случае наличия RAII в языке, будем возвращать специальный объект для автоматического отпускания мьютекса, точно так же, как и в Rust. ИД>RAII -- это не самое интересное (хоть и важное). Интересная часть -- это borrow checker. После захвата мьютекса, ты можешь получить обычную ссылку на внутренние данные -- и распоряжаться ей как тебе вздумается. Например, сохранить в какой-то структуре и отправить куда-нибудь. Можно даже взять ссылку на часть данных, засунуть в другую структуру и вызвать какую-нибудь функцию. Но только соблюдая условия заимствования -- ты не можешь заимствовать дольше, чем будет захвачен мьютекс. ИД>Например. ИД>Первый комментарий -- я использовал Rc, который небезопасен в многопоточном коде. Второй комментарий -- поток может жить дольше, чем обрамляющий main.
Я в курсе, что Rust позволяет отслеживать жизненный путь ссылки. Но гарантию корректности даже этого простейшего нюанса (который в реальности не гарантирует корректность многопоточности в целом) мы можем дать только в том случае, если административными методами (т.к. для данного действия не требуется unsafe блок) запретить операцию получения голого указателя из этой ссылки. Да, для использования этого указателя требуется unsafe код, но он может располагаться в совершенно другом модуле приложения и даже в какой-то библиотеке (например написанной на другом языке) — для передачи таких указателей опять же не требуется каких-то unsafe модификаторов на пути. Т.е. по факту мы можем написать некий многопоточный код, даже без всякого явного unsafe в коде и получить при этом доступ к объекту не из под мьютекса. Т.е. гарантий нет даже в такой мелочи, которая сама по себе даже при гарантированной реализации не даёт гарантированно корректной многопоточности.
_>>Можно увидеть его точный аналог на Rust, с размещением данных внутри мьютекса? ) ИД>Что произойдёт в этом коде, если поток номер 15 выбросит исключение на "t.join()" (вернее, "t.join" для потока №15 выбросит исключение)? Для драматичности давай считать, что "main" -- это какая-то функция внутри большой системы.
Ну т.к. у меня не стоит своего обработчика прерываний, то будет вызван стандартный, который вызовет завершение приложения. Непонятно только к чему ты спросил такую очевидную вещь.
ИД>Или, например, "emplace_back" не сможет выделить память для последнего потока и тоже выбросит исключение.
Здравствуйте, Иван Дубров, Вы писали:
WH>>>Мне не нужен кусок говнокода, который ничего не делает. WH>>>Мне нужна реальная задача, при решении которой такое нужно. _>>Понятно. Ожидаемый слив. ))) ИД>В написанном виде этот код -- unsound, и Rust просто не даст его написать, borrow checker ругаться будет. Там возможна висящая ссылка.
Ну во-первых, как видишь уже имеем проблему Rust'а, что он не даёт реализовать совершенно нормальный пример напрямую.
А во-вторых, вообще то конкретно такая реализация не принципиальна — ну возьми вместо просто локальной переменной какой-нибудь Arc и т.п. И попробуй реализовать. Смысл моего примера был в одновременном использование двух переменных с разным временем жизни — абсолютно реальная ситуация, т.к. многие данные инициируются по ходу работы приложения.
Здравствуйте, alex_public, Вы писали:
_>Ну во-первых, как видишь уже имеем проблему Rust'а, что он не даёт реализовать совершенно нормальный пример напрямую.
Нет, не нормальный. В определенных ситуациях код будет продолжать использовать висящие ссылки (если потоки переживут вызов функции). Это как то, что я совсем не хочу сидеть и ревьювить в коде наших разработчиков. Потому что это весьма неочевидное поведение.
_>А во-вторых, вообще то конкретно такая реализация не принципиальна — ну возьми вместо просто локальной переменной какой-нибудь Arc и т.п. И попробуй реализовать. Смысл моего примера был в одновременном использование двух переменных с разным временем жизни — абсолютно реальная ситуация, т.к. многие данные инициируются по ходу работы приложения.
Эти примеры нельзя напрямую переносить в Rust, потому что в реальности будет какая-то другая задача. Если будет Arc, то данные, возможно, будут вообще неизменяемые и ничего синхронизовать не нужно. И так далее.
Да, есть определённые задачи, которые сложно решаются в Rust. Например, циклические структуры данных или так называемые self-referential структуры данных.
Здравствуйте, alex_public, Вы писали:
_>Я в курсе, что Rust позволяет отслеживать жизненный путь ссылки. Но гарантию корректности даже этого простейшего нюанса (который в реальности не гарантирует корректность многопоточности в целом) мы можем дать только в том случае, если административными методами (т.к. для данного действия не требуется unsafe блок) запретить операцию получения голого указателя из этой ссылки. Да, для использования этого указателя требуется unsafe код, но он может располагаться в совершенно другом модуле приложения и даже в какой-то библиотеке (например написанной на другом языке) — для передачи таких указателей опять же не требуется каких-то unsafe модификаторов на пути. Т.е. по факту мы можем написать некий многопоточный код, даже без всякого явного unsafe в коде и получить при этом доступ к объекту не из под мьютекса. Т.е. гарантий нет даже в такой мелочи, которая сама по себе даже при гарантированной реализации не даёт гарантированно корректной многопоточности.
Не совсем. unsafe код пишется из того расчёта, что через safe интерфейс вокруг этого кода нельзя нарушить инварианты Rust. То есть, если ты пишешь код который в safe функции принимает левый указатель и внутри unsafe блока его читает -- то этот код некорректный.
Поэтому, возвращаемся опять к исходной постановке: неважно, что там делает код во всей системе -- достаточно проанализировать код в окрестностях unsafe. "Административный метод" применяется на стороне unsafe кода, которого как я уже писал, у нас 5 штук на 200 тыс. строк кода.
Конечно, наверняка есть ошибки и просчёты, например, в библиотеках, которые таки-позволяют сломать систему, если постараться. В конце-концов, ошибки в компиляторе и так далее. Но меня больше практическая сторона волнует: как большой группой писать код на языке без GC и не получать всякие разные интересные проблемы с памятью.