Вот часто пишут, что задачи на собеседованиях оторваны от реальности. Я решил хоть на толику разрушить этот миф и опубликовать парочку вопросов, с которыми сталкивался по работе. Изначально я про них никому не рассказывал, думая, что вот когда-нибудь стану сениором-помидором и буду такой важный задавать хитрые задачки. Сейчас я не уверен, что хочу следовать этим путём, поэтому пусть хоть кто-то поломает голову =)
1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.
Сразу скажу, что решение я публиковать не буду. Но если кто-то решит тем способом, что решил я, я об этом сообщу. Могу лишь сказать, что у первой задачи есть поистине красивое с точки зрения кодирования решение, которое можно уместить буквально в несколько строк. Вторая задача не такая сложная, поэтому я ожидаю, что многие её быстро решат, но мне, опять же, понравилась простота решения. Что интересно, в отличие от первой задачи, изящное решение которой я нашёл просто от нечего делать, решение второй задачи было обусловлено именно такой постановкой: внезпно и вероломно обрушившийся говнокод стал причиной того, что робот зависал
, и мне так и сказали: "Рефакторить нет времени и вообще ты нам ещё тут пояснишь потом за технический дизайн, а сейчас быстро запилил мне однострочник, который решит проблему"
Здравствуйте, cppguard, Вы писали:
C>Переписать в нуля это всегда универсальное решение, если вы не FAANG, где можно бросить целый отдел на написание и поддержку библиотеки, то, увы, на практике оно непременимо.
Зависит. Некоторые вещи можно делать даже в одно рыло.
Здравствуйте, LaptevVV, Вы писали:
C>>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. LVV>Представление холста какое?
Векторное же. Грубо говоря задача сводится к расчёту точек пересечений линий и canvas bounding box
Здравствуйте, cppguard, Вы писали:
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
Тут должно быть просто: надо рассчитать шаг по x и по y и с этими шагами пройти по периметру прямоугольника... Только не понятно, что за шаг задан на входе? Расстояние между линиями? Тогда один шаг — это синус угла, второй — косинус, ну и цикл "по периметру"...
C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.
Просто в вставить вызов flush() после каждой записи данных на NFS.
Здравствуйте, cppguard, Вы писали:
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
Первое, что я бы сделал это мысленно расширил canvas по оси X влево и вправо на dx = h * tan(alpha) (максимальное расстояние на котором может находиться противоположная точка). Далее:
1. Выбираем начальную точку допустим на нижней стороне равную, например, x_down = -dx.
2. Вычисляем противоположную ей точку на верхней стороне, она будет равна x_up = x_down + dx.
3. Соединяем эти две точки. Если наш canvas не поддерживает выходы за границу, то придется искать точку пересечения с вертикальными сторонами.
4. Шагаем до тех пор пока x_down <= w + dx.
Если угол отрицательный, то просто шагаем точно так же, но по верхней стороне.
Здравствуйте, cppguard, Вы писали:
C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.
Ну первое что я бы сделал, преобразовал запись в NFS на не блокирующий вызов, чтобы в момент записи поток переключался на отправку прикладных данных. Плюс попытался бы приоритизировать прикладной TCP трафик через PSH/URG флаги.
Здравствуйте, cppguard, Вы писали:
C>Вот часто пишут, что задачи на собеседованиях оторваны от реальности. Я решил хоть на толику разрушить этот миф и опубликовать парочку вопросов, с которыми сталкивался по работе. Изначально я про них никому не рассказывал, думая, что вот когда-нибудь стану сениором-помидором и буду такой важный задавать хитрые задачки. Сейчас я не уверен, что хочу следовать этим путём, поэтому пусть хоть кто-то поломает голову =)
1 — это какой-то стандартный алгоритм, еще турбо паскаль умел в заливку многоугольников.
2 — клиент шлет файлы на сервер через тот же TCP/IP и уже сервер пишет их в NFS (или в локальный каталог, я не очень хорошо знаком с NFS)?
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д.
А можно для тех кто не очень знаком к векторной графикой перечислить эти функции?
C>В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом.
Не очень понятно что значит заштрихован.
Линии под углом, от одного края до другого?
вот так?
Здравствуйте, scf, Вы писали:
scf>1 — это какой-то стандартный алгоритм, еще турбо паскаль умел в заливку многоугольников.
Залить и заштриховать это разные вещи.
scf>2 — клиент шлет файлы на сервер через тот же TCP/IP и уже сервер пишет их в NFS (или в локальный каталог, я не очень хорошо знаком с NFS)?
Для клиента NFS выглядит как обычная файловая система, соответственно, чтение и запись файлов происходит через стандартные для этого функции. Данные на сервер отправляет драйвер NFS.
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
Представление холста какое?
Если пиксельное, то алгоритм Брезенхема.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, cppguard, Вы писали:
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
Холст прямоугольный? Зная угол и шаг, найти шаги по горизонтальной/вертикальной границе и шагать.
Здравствуйте, CreatorCray, Вы писали:
CC>Векторное же. Грубо говоря задача сводится к расчёту точек пересечений линий и canvas bounding box
Всё верно. Соль в том, что в зависимости от угла наклона линий точки концов одной линии могут быть располагаться как на соседних сторонах прямоугольника, так и на противоположных.
Здравствуйте, Ip Man, Вы писали:
IM>Холст прямоугольный? Зная угол и шаг, найти шаги по горизонтальной/вертикальной границе и шагать.
Верно, но концы одной линии могут оказаться как на соседних сторонах, так и на противоположных. Я сначала такое решение и написал, и столкнулся с тем, что слишком много if-ов было.
Здравствуйте, cppguard, Вы писали:
C>Всё верно. Соль в том, что в зависимости от угла наклона линий точки концов одной линии могут быть располагаться как на соседних сторонах прямоугольника, так и на противоположных.
Это как раз не проблема вовсе: считаешь оба пересечения, берёшь ближайшее.
Здравствуйте, cppguard, Вы писали:
C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны.
Можно, например, написать клиента NFS: https://github.com/Cyberax/go-nfs-client — это примерно так 500 строк кода на Питоне, не считая сгенерированного кода RPC-обёрток. Или взять готового (есть обёртки для libnfs).
Ну а дальше просто на прикладном уровне делать rate-limit/приоритизацию для трафика.
Здравствуйте, cppguard, Вы писали:
C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.
Вроде это не про программирование как таковое, т.к. тут писать ничего не надо. У NFS и основного траффика будут разные порты, хотя и один и тот же хост назначения. Значит всё это довольно легко и просто решается через правила iptables или что там на машине вместо него.
Здравствуйте, kaa.python, Вы писали:
KP>Вроде это не про программирование как таковое, т.к. тут писать ничего не надо. У NFS и основного траффика будут разные порты, хотя и один и тот же хост назначения. Значит всё это довольно легко и просто решается через правила iptables или что там на машине вместо него.
Разбираемся. Во-первых, iptables, как и любой другой firewall, не позволяет настроить приоритезацию трафика. Это можно сделать в ядре, поменяв queuing discipline. Но проблема остаётся — запись в файл и запись прикладных данных в порт не могут быть параллельными, потому что GIL, и очередной вызов write(2) может вызвать сброс буфера NFS, что приведёт к долгой паузе.
Здравствуйте, Cyberax, Вы писали:
C>Можно, например, написать клиента NFS: https://github.com/Cyberax/go-nfs-client — это примерно так 500 строк кода на Питоне, не считая сгенерированного кода RPC-обёрток. Или взять готового (есть обёртки для libnfs).
C>Ну а дальше просто на прикладном уровне делать rate-limit/приоритизацию для трафика.
Переписать в нуля это всегда универсальное решение, если вы не FAANG, где можно бросить целый отдел на написание и поддержку библиотеки, то, увы, на практике оно непременимо.
Здравствуйте, CreatorCray, Вы писали:
C>>Всё верно. Соль в том, что в зависимости от угла наклона линий точки концов одной линии могут быть располагаться как на соседних сторонах прямоугольника, так и на противоположных. CC>Это как раз не проблема вовсе: считаешь оба пересечения, берёшь ближайшее.
Ну так-то да =) Но это решение в лоб с переходом от целых чисел к дробным, ещё нужно аккуратно посчитать округление и протестировать все условные переходы.
Здравствуйте, cppguard, Вы писали:
C>Разбираемся. Во-первых, iptables, как и любой другой firewall, не позволяет настроить приоритезацию трафика. Это можно сделать в ядре, поменяв queuing discipline. Но проблема остаётся — запись в файл и запись прикладных данных в порт не могут быть параллельными, потому что GIL, и очередной вызов write(2) может вызвать сброс буфера NFS, что приведёт к долгой паузе.
В iptables ты можешь использоваться (hash)limit и отбрасывать часть пакетов NFS что даст преимущество твоему стандартному трафику. GIL всегда легко обходился через multiprocessing, куда вполне можно затолкать записать в/из файла и сокеты в NFS. Это, конечно, кривое решение, но ты же сам просил самое короткое, правильные тебе не нравятся
Здравствуйте, cppguard, Вы писали:
C>Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время.
Что-то не очень распарсил выделенное, ну да ладно.
Это ж питон, да? Ну нельзя поток, запусти процесс, делов-то.
Можно вообще ковбойским методом решить — писать в локальный storage, и запустить (периодически запускать) внешний
Здравствуйте, cppguard, Вы писали:
C>клиенту нельзя создавать параллельные потоки из-за наличия GIL
А не пробовали более нормальные клиенты писать? Например, на яве.
И кстати, я не понимаю, каким образом GIL питона может влиять на создание дополнительных потоков внутри кода на C++, который эти запросы обрабатывает. Вы ведь на C++ пишете? Или на питоне обслуживаете этсамое, обоснование необходимости носить маски и сидеть дома, с помощью Машинного Обучения и Искусственного Интеллекта?
Здравствуйте, cppguard, Вы писали:
C>>Ну а дальше просто на прикладном уровне делать rate-limit/приоритизацию для трафика. C>Переписать в нуля это всегда универсальное решение, если вы не FAANG, где можно бросить целый отдел на написание и поддержку библиотеки, то, увы, на практике оно непременимо.
Ну вот эту библиотеку я написал за 1 день (плюс ещё день на допиливание). Она уже как год работает без единого нарекания, на уже петабайтах данных.
Здравствуйте, Слава, Вы писали:
С>И кстати, я не понимаю, каким образом GIL питона может влиять на создание дополнительных потоков внутри кода на C++, который эти запросы обрабатывает. Вы ведь на C++ пишете? Или на питоне обслуживаете этсамое, обоснование необходимости носить маски и сидеть дома, с помощью Машинного Обучения и Искусственного Интеллекта?
Здравствуйте, blacktea, Вы писали:
B>Ну первое что я бы сделал, преобразовал запись в NFS на не блокирующий вызов, чтобы в момент записи поток переключался на отправку прикладных данных. Плюс попытался бы приоритизировать прикладной TCP трафик через PSH/URG флаги.
Вы близки к моему решению. Осталось только решить небольшую проблему — write(2) для обычного файла (напомню, работа с NFS выполняется через файловый интерфейс) не поддерживает неблокирующийся режим.
Здравствуйте, blacktea, Вы писали:
B>Первое, что я бы сделал это мысленно расширил canvas по оси X влево и вправо на dx = h * tan(alpha) (максимальное расстояние на котором может находиться противоположная точка). Далее: B>1. Выбираем начальную точку допустим на нижней стороне равную, например, x_down = -dx. B>2. Вычисляем противоположную ей точку на верхней стороне, она будет равна x_up = x_down + dx. B>3. Соединяем эти две точки. Если наш canvas не поддерживает выходы за границу, то придется искать точку пересечения с вертикальными сторонами. B>4. Шагаем до тех пор пока x_down <= w + dx. B>Если угол отрицательный, то просто шагаем точно так же, но по верхней стороне.
Направление правильное, но всё ещё есть место для упрощения
Здравствуйте, kaa.python, Вы писали:
KP>В iptables ты можешь использоваться (hash)limit и отбрасывать часть пакетов NFS что даст преимущество твоему стандартному трафику. GIL всегда легко обходился через multiprocessing, куда вполне можно затолкать записать в/из файла и сокеты в NFS. Это, конечно, кривое решение, но ты же сам просил самое короткое, правильные тебе не нравятся
Решение с отбрасыванием пакетов не масштабируется. Если расчитать rate так, чтобы удовлетворить по времени работу одного клиента, то невозможно будет запустить параллельно несколько клиентов. Ну и вообще кривое решение. Насчёт "правильного" решения — может быть, я ж не отрицаю такой вариант, просто считаю, что написание своей библиотеки это крайние меры. Оттого и растут бюджеты и команды, что едва столкнувшись с трудностями, говорят "а давайте всё перепешем на Х, Y слишком медленный!".
Здравствуйте, B0FEE664, Вы писали:
BFE>Тут должно быть просто: надо рассчитать шаг по x и по y и с этими шагами пройти по периметру прямоугольника... Только не понятно, что за шаг задан на входе? Расстояние между линиями? Тогда один шаг — это синус угла, второй — косинус, ну и цикл "по периметру"...
Верное решение. Нужно только правильно реализовать "цикл по периметру".
BFE>Просто в вставить вызов flush() после каждой записи данных на NFS.
flush() не дотягивается до внутренностей NFS, этот вызов говорит сбросить внутренний буфер ОС, передав содержимое драйверу. В случае с обычным диском, это приводит к физической записи (а может и нет ), но у NFS свой буфер для отложенной записи по сети.
Здравствуйте, cppguard, Вы писали:
C>Здравствуйте, Слава, Вы писали:
С>>И кстати, я не понимаю, каким образом GIL питона может влиять на создание дополнительных потоков внутри кода на C++, который эти запросы обрабатывает. Вы ведь на C++ пишете? Или на питоне обслуживаете этсамое, обоснование необходимости носить маски и сидеть дома, с помощью Машинного Обучения и Искусственного Интеллекта?
C>Код на питоне, так исторически сложилось.
Ну, Cyberax уже написал всё, что он думает. Дескать, пишите свой клиент.
От себя я добавлю — а что будет, если NFS на той стороне начнёт тормозить? Непредсказуемые задержки решаются буфером непредсказуемого размера, а вообще вместо прямой записи в NFS по-хорошему следует взять Apache Kafka, её сломать очень тяжело. Вот пусть она в файлы и пишет, когда сможет.
Здравствуйте, Слава, Вы писали:
С>От себя я добавлю — а что будет, если NFS на той стороне начнёт тормозить? Непредсказуемые задержки решаются буфером непредсказуемого размера, а вообще вместо прямой записи в NFS по-хорошему следует взять Apache Kafka, её сломать очень тяжело. Вот пусть она в файлы и пишет, когда сможет.
Я понимаю, что без знания других других деталей кажется, что ограничения странноваты. На то были свои причины. NFS даёт прозрачность на уровне драйвера файловой системы. Код, который писал в NFS, управлял манипулятором робота и в NFS писал свои логи. Логи нельзя было терять ни на бит, потому что потом по ним восстанавливалась история работы манипулятора и анализировались проблемы. Другой особенностью записи в логи было то, что роботы работали в полях, и единственным транспортом данных с них были флеш накопители, которые хитрым образом ротировались, и когда наступал конец смены очередного сотрудника, он сгребал флешки с логами и мчал из полей домой. Но помимо боевого режима, когда на одном роботе установлено до четырёх манипуляторов, были различные режимы эмуляции: от полностью программной, до частично аппаратной, до режима, когда весь робот потушен, и только манипулятор активен. Чтобы для каждого сценария не выстраивать заглушки и прочее, было решено использовать NFS, потому что тогда можно смонтировать каталог с логами и в tmpfs, и на локальный диск, и вообще везде, для чего существуют драйверы ФС.
P.S. Вот эта особенность, что нельзя прийти и сказать: "А давайте развернём на роботе 100 микросервисов, которые каждый будут тупить и жрать по 1GB, и ещё постоянно падать?" невероятно привлекала лично меня. Потому что во всяких облачных сервисах царит марафон безумия. Я лично видел, как один и тот же сервис переписывался на трёх разных языках под предлогом того, что каждая очередная смена считалась перспективной в плане производительности.
Здравствуйте, cppguard, Вы писали:
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
В комп. графике в свое время удивляло, что программистские придумки, пусть даже удачные, остроумные, но без особого рокет сайенса с матаном, называют именами тех, кто это опубликовал. Алгоритм Брезенхема, шейдинг Гуро, Фонга... Может, именовали для краткости, референса на конкретный способ.
Здравствуйте, cppguard, Вы писали:
C>Код, который писал в NFS, управлял манипулятором робота и в NFS писал свои логи. Логи нельзя было терять ни на бит, C>P.S. Вот эта особенность, что нельзя прийти и сказать: "А давайте развернём на роботе 100 микросервисов,
Спасибо за подробное пояснение.
Здесь мои знания ограничены, как мне всегда казалось, NFS надёжностью не отличается. Тогда, если хочется надёжных логов, почему нельзя писать в SQLite прямо из процесса, без NFS? Прямо в файлы я бы писать не стал, именно из соображений надёжности хранилища, потому что поломать файл можно сотней разных способов, БД от этого изолирует.
PS: а на Аде у вас пишут? Или не у вас, а у коллег. Потому что робот на питоне — это как-то гм.
Здравствуйте, Слава, Вы писали:
С>Спасибо за подробное пояснение.
С>Здесь мои знания ограничены, как мне всегда казалось, NFS надёжностью не отличается. Тогда, если хочется надёжных логов, почему нельзя писать в SQLite прямо из процесса, без NFS? Прямо в файлы я бы писать не стал, именно из соображений надёжности хранилища, потому что поломать файл можно сотней разных способов, БД от этого изолирует.
Файл поломать невозможно, потому что запись построчная, и даже вылетевший процесс может, максимум, испортить одну строчку. Я не знаю про надёжность NFS, у нас не было случаев порчи данных (при обороте около 1GB/day в течение года), а на сервере физическую ФС можно настроить с нужным уровнем отказоустойчивости. Впрочем, мы писали в ext4 =) SQLite тоже использовалась, но для другого. Сырая запись в файл, всё же, быстрее, и вот, как раз, БД легче испортить, в восстановить невозможно (уже разбирались с этим). Кроме того, контроллер манипулятора был thin client, то есть загружался по сети и не должен был хранить какого-либо состояния, NFS в этом случае снова выручал.
С>PS: а на Аде у вас пишут? Или не у вас, а у коллег. Потому что робот на питоне — это как-то гм.
Питон был выбран техдиректором по принципу "С++ никто не знает, поэтому пишем на питоне, чтобы никто ничего не ломал". Но это не помогло, и переодически робот выдавал курьёзы, которые никто не мог объяснить =) Это был первый в моей жизни опыт работы с роботами, поэтому про остальной рынок сказать не могу. Знаю, что многие плотно сидят на ROS, а это, опять же, Python. Кстати, с питоном легко было добиться квази-детерминированности: сборку мусора мы отключили, за непоявлением циклических зависимостей пристально следили, ввод/вывод за счёт наличия GIL (да-да, того самого) выстраивался в линию. Проблема была только с качеством кода, отсутствием какого-либо статического анализа. Частично эта проблема могла бы решиться за счёт соблюдения жёсткого coding guidelines с активным использованием defensive programming, но ребята на проекте были довольно хиповые и забородили мои идеи в этом направлении.
Здравствуйте, cppguard, Вы писали:
C>Питон был выбран техдиректором по принципу "С++ никто не знает, поэтому пишем на питоне, чтобы никто ничего не ломал". Но это не помогло, и переодически робот выдавал курьёзы, которые никто не мог объяснить =) Это был первый в моей жизни опыт работы с роботами, поэтому про остальной рынок сказать не могу. Знаю, что многие плотно сидят на ROS, а это, опять же, Python.
В ROS использование Python разве что для прототипирования. Робота написанного на динамически типизируемом языке ты потом устанешь сертифицировать на соответствие очередному заковыристому ISO.
Здравствуйте, kaa.python, Вы писали:
KP>Её вроде в авиации любят. Автомобилестроение любит C++. Робот на Питоне — это просто прототип уровня "купите наш прекрасный стартап".
И на Python можно написать надёжный код, было бы желание. Но в случае с тем роботом, действительно "купите стартап" =) Кстати, С++ во всяких автопилотах это тоже уровень "пыщь-пыщь, у нас автопилот не хуже теслы!", потому что по-нормальному mission critical пишется на Си или Ада, потом формально верефицируется. Может, конечно, научились делать верификацию С++, но я пока не слышал об этом.
Здравствуйте, kaa.python, Вы писали:
KP>В ROS использование Python разве что для прототипирования. Робота написанного на динамически типизируемом языке ты потом устанешь сертифицировать на соответствие очередному заковыристому ISO.
Формально, да, почти любого робота, который умеет взаимодействовать с внешней средой, нужно сертифицировать, потому что так или иначе робот попадает код какой-то вид оборудования. Но на практике почти никогда не приходится это делать. В моём случае робот собирал урожай с полей и технически его могли записать как обычный трактор, потому что присутствовал HMI в виде джойстика. А автопилот теслы это "всего лишь ADAS, а не автопилот, поэтому идите лесом".
P.S. Когда в США всех погнали ссаными тряпками на самоизоляцию, наш босс сказал, что мы работаем в сельскохозяйственной области, а это essential business, и всех оставили в офисе Вот примерно такой же подход и к сертификации.
Здравствуйте, cppguard, Вы писали:
C>И на Python можно написать надёжный код, было бы желание.
Как раз никак нельзя. Ты не контролируешь выделение и освобождение памяти, что критично. Ты не можешь провести статический анализ кода, что так же критично.
C> Но в случае с тем роботом, действительно "купите стартап" =) Кстати, С++ во всяких автопилотах это тоже уровень "пыщь-пыщь, у нас автопилот не хуже теслы!", потому что по-нормальному mission critical пишется на Си или Ада, потом формально верефицируется. Может, конечно, научились делать верификацию С++, но я пока не слышал об этом.
Mission critical (ASIL D) пишется на C++14, смотри AUTOSAR C++14. Так же есть MISRA C++, но там совсем всё дремучее. Статические анализаторы тоже есть, причем сертифицированные по ISO 26262. Так же стоит учитывать что к mission critical относится очень небольшая часть компонент в машине, основная масса обычный QM, остальная на обычном C++. В теории остальное можно и на Python написать, конечно, но оно ж тырндец падучее и тормознутое будет.
Здравствуйте, kaa.python, Вы писали:
KP>Как раз никак нельзя. Ты не контролируешь выделение и освобождение памяти, что критично. Ты не можешь провести статический анализ кода, что так же критично.
Речь о Python или о CPython? Это раз. Отключается сборка мусора, остаётся только подсчёт ссылок. malloc/free пишутся свои. Кроме того, питон позволяет перехватывать вызов аллокатора через переопределение __new__ и переиспользовать память. Я таким образом реализовал FSM в неявном виде: переход в новое состояние определялся возвратом нового объекта, но объект реально не создавался, а переинициализировался. Я не хочу спорить, что Питон это не самый луший выбор для робота, но я не люблю, когда говорят "X — слишком медленный/прожорливый/старый/негибкий для этой задачи", я вместо этого думаю, что программисты бывают недостаточно квалифицированы для задачи.
C>> Но в случае с тем роботом, действительно "купите стартап" =) Кстати, С++ во всяких автопилотах это тоже уровень "пыщь-пыщь, у нас автопилот не хуже теслы!", потому что по-нормальному mission critical пишется на Си или Ада, потом формально верефицируется. Может, конечно, научились делать верификацию С++, но я пока не слышал об этом.
KP>Mission critical (ASIL D) пишется на C++14, смотри AUTOSAR C++14. Так же есть MISRA C++, но там совсем всё дремучее. Статические анализаторы тоже есть, причем сертифицированные по ISO 26262. Так же стоит учитывать что к mission critical относится очень небольшая часть компонент в машине, основная масса обычный QM, остальная на обычном C++. В теории остальное можно и на Python написать, конечно, но оно ж тырндец падучее и тормознутое будет.
MISRA это стандарт, а не метод. Ну ок, проверили, что соответствует MISRA, а дальше что? Я не говорю, что на С++ невозможно писать mission critical, просто возни больше, а плюсов меньше.
KP> В теории остальное можно и на Python написать, конечно, но оно ж тырндец падучее и тормознутое будет.
Если программист нормальный то не будет. Вопрос в другом — где взять сертифицированный интерпретатор?
P.S. Не совсем в тему. На текущем проекте (никак не связанном с роботами или automotive) полным ходом идёт миграция пользователей на новый движок обработки потоковых данных (real-time stream processing). Предыдущий был написан на Java и лишь немного подъедал память (код там не самый лучший), но был объявлен медленным (да-да, та самая медленная ява). Новый движок на С++, и я то и дело слышу, что что-то там упало. Видимо, те крохи времени, которые выигрываются при переходе с JVM на native стоят постоянной головной боли. При этом у меня есть личный сторонний проект на Java, тоже связанный с потоковой обработкой данных, в нём все летает, ничего не падает, аптайм исчисляется месяцами
Здравствуйте, cppguard, Вы писали:
C>Речь о Python или о CPython? Это раз. Отключается сборка мусора, остаётся только подсчёт ссылок. malloc/free пишутся свои. Кроме того, питон позволяет перехватывать вызов аллокатора через переопределение __new__ и переиспользовать память. Я таким образом реализовал FSM в неявном виде: переход в новое состояние определялся возвратом нового объекта, но объект реально не создавался, а переинициализировался.
А с динамической типизацией ты что сделать предлагаешь? Код который верфицируется только во время выполнения, это, ну, "такое" для робота.
C>Я не хочу спорить, что Питон это не самый луший выбор для робота, но я не люблю, когда говорят "X — слишком медленный/прожорливый/старый/негибкий для этой задачи", я вместо этого думаю, что программисты бывают недостаточно квалифицированы для задачи.
Есть альтернативный вариант на это взглянуть — есть программисты которые не посмотрели на предметную область достаточно глубоко и тянут туда привычные, но не подходящие инструменты.
C>MISRA это стандарт, а не метод. Ну ок, проверили, что соответствует MISRA, а дальше что? Я не говорю, что на С++ невозможно писать mission critical, просто возни больше, а плюсов меньше.
Плюсов больше — есть куча библиотек и готовых специалистов, писать опять таки проще чем на Си.
C>Если программист нормальный то не будет. Вопрос в другом — где взять сертифицированный интерпретатор?
Нигде, его тебе не сертифицируют, т.к. весь код должен быть проверен на этапе верификации, но это не возможно сделать для динамической типизации.
C>P.S. Не совсем в тему. На текущем проекте (никак не связанном с роботами или automotive) полным ходом идёт миграция пользователей на новый движок обработки потоковых данных (real-time stream processing). Предыдущий был написан на Java и лишь немного подъедал память (код там не самый лучший), но был объявлен медленным (да-да, та самая медленная ява). Новый движок на С++, и я то и дело слышу, что что-то там упало.
Java не медленная ни разу, только стартует долго. То что в плюсах что-то падает — так руки из жопы, у нас, почему-то, я за полтора года вообще не видел падений C++ кода. Магия?