Пара задач из жизни
От: cppguard  
Дата: 03.12.21 16:15
Оценка: 8 (2)
Вот часто пишут, что задачи на собеседованиях оторваны от реальности. Я решил хоть на толику разрушить этот миф и опубликовать парочку вопросов, с которыми сталкивался по работе. Изначально я про них никому не рассказывал, думая, что вот когда-нибудь стану сениором-помидором и буду такой важный задавать хитрые задачки. Сейчас я не уверен, что хочу следовать этим путём, поэтому пусть хоть кто-то поломает голову =)

1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.

2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.

Сразу скажу, что решение я публиковать не буду. Но если кто-то решит тем способом, что решил я, я об этом сообщу. Могу лишь сказать, что у первой задачи есть поистине красивое с точки зрения кодирования решение, которое можно уместить буквально в несколько строк. Вторая задача не такая сложная, поэтому я ожидаю, что многие её быстро решат, но мне, опять же, понравилась простота решения. Что интересно, в отличие от первой задачи, изящное решение которой я нашёл просто от нечего делать, решение второй задачи было обусловлено именно такой постановкой: внезпно и вероломно обрушившийся говнокод стал причиной того, что робот зависал
Автор: cppguard
Дата: 07.11.20
, и мне так и сказали: "Рефакторить нет времени и вообще ты нам ещё тут пояснишь потом за технический дизайн, а сейчас быстро запилил мне однострочник, который решит проблему"
Re[3]: Пара задач из жизни
От: CreatorCray  
Дата: 05.12.21 07:46
Оценка: +2
Здравствуйте, cppguard, Вы писали:

C>Переписать в нуля это всегда универсальное решение, если вы не FAANG, где можно бросить целый отдел на написание и поддержку библиотеки, то, увы, на практике оно непременимо.


Зависит. Некоторые вещи можно делать даже в одно рыло.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re[2]: Пара задач из жизни
От: CreatorCray  
Дата: 04.12.21 08:03
Оценка: +1
Здравствуйте, LaptevVV, Вы писали:

C>>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д.

LVV>Представление холста какое?
Векторное же. Грубо говоря задача сводится к расчёту точек пересечений линий и canvas bounding box
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re: Пара задач из жизни
От: B0FEE664  
Дата: 05.12.21 15:02
Оценка: +1
Здравствуйте, cppguard, Вы писали:

C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.


Тут должно быть просто: надо рассчитать шаг по x и по y и с этими шагами пройти по периметру прямоугольника... Только не понятно, что за шаг задан на входе? Расстояние между линиями? Тогда один шаг — это синус угла, второй — косинус, ну и цикл "по периметру"...

C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.


Просто в вставить вызов flush() после каждой записи данных на NFS.
И каждый день — без права на ошибку...
Re: Пара задач из жизни
От: blacktea  
Дата: 05.12.21 17:22
Оценка: +1
Здравствуйте, 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.
Если угол отрицательный, то просто шагаем точно так же, но по верхней стороне.
Re: Пара задач из жизни
От: blacktea  
Дата: 05.12.21 17:55
Оценка: +1
Здравствуйте, cppguard, Вы писали:

C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.


Ну первое что я бы сделал, преобразовал запись в NFS на не блокирующий вызов, чтобы в момент записи поток переключался на отправку прикладных данных. Плюс попытался бы приоритизировать прикладной TCP трафик через PSH/URG флаги.
Re: Пара задач из жизни
От: scf  
Дата: 03.12.21 16:25
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Вот часто пишут, что задачи на собеседованиях оторваны от реальности. Я решил хоть на толику разрушить этот миф и опубликовать парочку вопросов, с которыми сталкивался по работе. Изначально я про них никому не рассказывал, думая, что вот когда-нибудь стану сениором-помидором и буду такой важный задавать хитрые задачки. Сейчас я не уверен, что хочу следовать этим путём, поэтому пусть хоть кто-то поломает голову =)


1 — это какой-то стандартный алгоритм, еще турбо паскаль умел в заливку многоугольников.

2 — клиент шлет файлы на сервер через тот же TCP/IP и уже сервер пишет их в NFS (или в локальный каталог, я не очень хорошо знаком с NFS)?
Re: Пара задач из жизни
От: Muxa  
Дата: 03.12.21 16:33
Оценка:
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д.
А можно для тех кто не очень знаком к векторной графикой перечислить эти функции?

C>В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом.

Не очень понятно что значит заштрихован.

Линии под углом, от одного края до другого?
вот так?

Re[2]: Пара задач из жизни
От: cppguard  
Дата: 04.12.21 07:10
Оценка:
Здравствуйте, Muxa, Вы писали:

M>А можно для тех кто не очень знаком к векторной графикой перечислить эти функции?


https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API

M>Не очень понятно что значит заштрихован.

M>Линии под углом, от одного края до другого?
M>вот так?
M>Image: SBWBJ.png

Именно так
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 04.12.21 07:11
Оценка:
Здравствуйте, scf, Вы писали:

scf>1 — это какой-то стандартный алгоритм, еще турбо паскаль умел в заливку многоугольников.


Залить и заштриховать это разные вещи.

scf>2 — клиент шлет файлы на сервер через тот же TCP/IP и уже сервер пишет их в NFS (или в локальный каталог, я не очень хорошо знаком с NFS)?


Для клиента NFS выглядит как обычная файловая система, соответственно, чтение и запись файлов происходит через стандартные для этого функции. Данные на сервер отправляет драйвер NFS.
Re: Пара задач из жизни
От: LaptevVV Россия  
Дата: 04.12.21 07:20
Оценка:
C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.
Представление холста какое?
Если пиксельное, то алгоритм Брезенхема.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Пара задач из жизни
От: Ip Man Китай  
Дата: 04.12.21 08:26
Оценка:
Здравствуйте, cppguard, Вы писали:

C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.


Холст прямоугольный? Зная угол и шаг, найти шаги по горизонтальной/вертикальной границе и шагать.
Re[3]: Пара задач из жизни
От: cppguard  
Дата: 05.12.21 01:08
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>Векторное же. Грубо говоря задача сводится к расчёту точек пересечений линий и canvas bounding box


Всё верно. Соль в том, что в зависимости от угла наклона линий точки концов одной линии могут быть располагаться как на соседних сторонах прямоугольника, так и на противоположных.
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 05.12.21 01:10
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Если пиксельное, то алгоритм Брезенхема.


Линейная зависимость от размера холста, а нужна константа.
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 05.12.21 01:11
Оценка:
Здравствуйте, Ip Man, Вы писали:

IM>Холст прямоугольный? Зная угол и шаг, найти шаги по горизонтальной/вертикальной границе и шагать.


Верно, но концы одной линии могут оказаться как на соседних сторонах, так и на противоположных. Я сначала такое решение и написал, и столкнулся с тем, что слишком много if-ов было.
Re[4]: Пара задач из жизни
От: CreatorCray  
Дата: 05.12.21 03:33
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Всё верно. Соль в том, что в зависимости от угла наклона линий точки концов одной линии могут быть располагаться как на соседних сторонах прямоугольника, так и на противоположных.

Это как раз не проблема вовсе: считаешь оба пересечения, берёшь ближайшее.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re: Пара задач из жизни
От: Cyberax Марс  
Дата: 05.12.21 04:41
Оценка:
Здравствуйте, cppguard, Вы писали:

C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны.

Можно, например, написать клиента NFS: https://github.com/Cyberax/go-nfs-client — это примерно так 500 строк кода на Питоне, не считая сгенерированного кода RPC-обёрток. Или взять готового (есть обёртки для libnfs).

Ну а дальше просто на прикладном уровне делать rate-limit/приоритизацию для трафика.
Sapienti sat!
Re: Пара задач из жизни
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 05.12.21 05:23
Оценка:
Здравствуйте, cppguard, Вы писали:

C>2. Имеются две программы: клиент и сервер. Клиент общается с сервером через TCP/IP и одновременно пишет в сетевую файловую систему (NFS), которая физически расположена на той же машине, что и серверный процесс. Таким образом получается два типа очень активного траффика: прикладной и NFS. Прикладной трафик является очень важным и должен доходить до сервера с минимальными задержками, трафик NFS тоже является важным, но время тут некритично, важно, чтобы данные в конечном итоге были записаны. Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время. Задачу нужно решить с минимальными модификациями.


Вроде это не про программирование как таковое, т.к. тут писать ничего не надо. У NFS и основного траффика будут разные порты, хотя и один и тот же хост назначения. Значит всё это довольно легко и просто решается через правила iptables или что там на машине вместо него.
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 05.12.21 06:59
Оценка:
Здравствуйте, kaa.python, Вы писали:

KP>Вроде это не про программирование как таковое, т.к. тут писать ничего не надо. У NFS и основного траффика будут разные порты, хотя и один и тот же хост назначения. Значит всё это довольно легко и просто решается через правила iptables или что там на машине вместо него.


Разбираемся. Во-первых, iptables, как и любой другой firewall, не позволяет настроить приоритезацию трафика. Это можно сделать в ядре, поменяв queuing discipline. Но проблема остаётся — запись в файл и запись прикладных данных в порт не могут быть параллельными, потому что GIL, и очередной вызов write(2) может вызвать сброс буфера NFS, что приведёт к долгой паузе.
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 05.12.21 07:01
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Можно, например, написать клиента NFS: https://github.com/Cyberax/go-nfs-client — это примерно так 500 строк кода на Питоне, не считая сгенерированного кода RPC-обёрток. Или взять готового (есть обёртки для libnfs).


C>Ну а дальше просто на прикладном уровне делать rate-limit/приоритизацию для трафика.


Переписать в нуля это всегда универсальное решение, если вы не FAANG, где можно бросить целый отдел на написание и поддержку библиотеки, то, увы, на практике оно непременимо.
Re[5]: Пара задач из жизни
От: cppguard  
Дата: 05.12.21 07:03
Оценка:
Здравствуйте, CreatorCray, Вы писали:

C>>Всё верно. Соль в том, что в зависимости от угла наклона линий точки концов одной линии могут быть располагаться как на соседних сторонах прямоугольника, так и на противоположных.

CC>Это как раз не проблема вовсе: считаешь оба пересечения, берёшь ближайшее.

Ну так-то да =) Но это решение в лоб с переходом от целых чисел к дробным, ещё нужно аккуратно посчитать округление и протестировать все условные переходы.
Re[3]: Пара задач из жизни
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 05.12.21 07:55
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Разбираемся. Во-первых, iptables, как и любой другой firewall, не позволяет настроить приоритезацию трафика. Это можно сделать в ядре, поменяв queuing discipline. Но проблема остаётся — запись в файл и запись прикладных данных в порт не могут быть параллельными, потому что GIL, и очередной вызов write(2) может вызвать сброс буфера NFS, что приведёт к долгой паузе.


В iptables ты можешь использоваться (hash)limit и отбрасывать часть пакетов NFS что даст преимущество твоему стандартному трафику. GIL всегда легко обходился через multiprocessing, куда вполне можно затолкать записать в/из файла и сокеты в NFS. Это, конечно, кривое решение, но ты же сам просил самое короткое, правильные тебе не нравятся
Автор: Cyberax
Дата: 05.12.21
Отредактировано 05.12.2021 7:59 kaa.python . Предыдущая версия . Еще …
Отредактировано 05.12.2021 7:56 kaa.python . Предыдущая версия .
Re: Пара задач из жизни
От: landerhigh Пират  
Дата: 05.12.21 22:41
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Так же важно, что клиенту нельзя создавать параллельные потоки из-за наличия GIL, но можно использовать неблокирующийся ввод/вывод. Характер работы NFS таков, что данные сперва пишутся в локальный буфер, и когда он накапливается, содержимое буфера отсылается по сети, и происходит запись в файловую систему. Настроить параметры этого процесса практически невозможно, и это становится проблемой — в момент, когда данные из буфера пересылаются по сети, процесс клиента блокируется на непозволительно долгое время.


Что-то не очень распарсил выделенное, ну да ладно.
Это ж питон, да? Ну нельзя поток, запусти процесс, делов-то.

Можно вообще ковбойским методом решить — писать в локальный storage, и запустить (периодически запускать) внешний

cp /local/super/important/file.log /mnt/nfs/blah/blah
www.blinnov.com
Re: Пара задач из жизни
От: Слава  
Дата: 06.12.21 01:54
Оценка:
Здравствуйте, cppguard, Вы писали:

C>клиенту нельзя создавать параллельные потоки из-за наличия GIL


А не пробовали более нормальные клиенты писать? Например, на яве.

И кстати, я не понимаю, каким образом GIL питона может влиять на создание дополнительных потоков внутри кода на C++, который эти запросы обрабатывает. Вы ведь на C++ пишете? Или на питоне обслуживаете этсамое, обоснование необходимости носить маски и сидеть дома, с помощью Машинного Обучения и Искусственного Интеллекта?
Отредактировано 06.12.2021 2:02 Слава . Предыдущая версия .
Re[3]: Пара задач из жизни
От: Cyberax Марс  
Дата: 06.12.21 03:16
Оценка:
Здравствуйте, cppguard, Вы писали:

C>>Ну а дальше просто на прикладном уровне делать rate-limit/приоритизацию для трафика.

C>Переписать в нуля это всегда универсальное решение, если вы не FAANG, где можно бросить целый отдел на написание и поддержку библиотеки, то, увы, на практике оно непременимо.
Ну вот эту библиотеку я написал за 1 день (плюс ещё день на допиливание). Она уже как год работает без единого нарекания, на уже петабайтах данных.

И опять же, можно же взять https://github.com/sahlberg/libnfs-python — там тоже всё ОК.
Sapienti sat!
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 06.12.21 10:08
Оценка:
Здравствуйте, Слава, Вы писали:

С>И кстати, я не понимаю, каким образом GIL питона может влиять на создание дополнительных потоков внутри кода на C++, который эти запросы обрабатывает. Вы ведь на C++ пишете? Или на питоне обслуживаете этсамое, обоснование необходимости носить маски и сидеть дома, с помощью Машинного Обучения и Искусственного Интеллекта?


Код на питоне, так исторически сложилось.
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 06.12.21 10:10
Оценка:
Здравствуйте, blacktea, Вы писали:

B>Ну первое что я бы сделал, преобразовал запись в NFS на не блокирующий вызов, чтобы в момент записи поток переключался на отправку прикладных данных. Плюс попытался бы приоритизировать прикладной TCP трафик через PSH/URG флаги.


Вы близки к моему решению. Осталось только решить небольшую проблему — write(2) для обычного файла (напомню, работа с NFS выполняется через файловый интерфейс) не поддерживает неблокирующийся режим.
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 06.12.21 10:15
Оценка:
Здравствуйте, 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>Если угол отрицательный, то просто шагаем точно так же, но по верхней стороне.

Направление правильное, но всё ещё есть место для упрощения
Re[4]: Пара задач из жизни
От: cppguard  
Дата: 06.12.21 10:22
Оценка:
Здравствуйте, kaa.python, Вы писали:

KP>В iptables ты можешь использоваться (hash)limit и отбрасывать часть пакетов NFS что даст преимущество твоему стандартному трафику. GIL всегда легко обходился через multiprocessing, куда вполне можно затолкать записать в/из файла и сокеты в NFS. Это, конечно, кривое решение, но ты же сам просил самое короткое, правильные тебе не нравятся
Автор: Cyberax
Дата: 05.12.21


Решение с отбрасыванием пакетов не масштабируется. Если расчитать rate так, чтобы удовлетворить по времени работу одного клиента, то невозможно будет запустить параллельно несколько клиентов. Ну и вообще кривое решение. Насчёт "правильного" решения — может быть, я ж не отрицаю такой вариант, просто считаю, что написание своей библиотеки это крайние меры. Оттого и растут бюджеты и команды, что едва столкнувшись с трудностями, говорят "а давайте всё перепешем на Х, Y слишком медленный!".
Re[2]: Пара задач из жизни
От: cppguard  
Дата: 06.12.21 10:29
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Тут должно быть просто: надо рассчитать шаг по x и по y и с этими шагами пройти по периметру прямоугольника... Только не понятно, что за шаг задан на входе? Расстояние между линиями? Тогда один шаг — это синус угла, второй — косинус, ну и цикл "по периметру"...


Верное решение. Нужно только правильно реализовать "цикл по периметру".

BFE>Просто в вставить вызов flush() после каждой записи данных на NFS.


flush() не дотягивается до внутренностей NFS, этот вызов говорит сбросить внутренний буфер ОС, передав содержимое драйверу. В случае с обычным диском, это приводит к физической записи (а может и нет ), но у NFS свой буфер для отложенной записи по сети.
Re[3]: Пара задач из жизни
От: Слава  
Дата: 06.12.21 15:57
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Здравствуйте, Слава, Вы писали:


С>>И кстати, я не понимаю, каким образом GIL питона может влиять на создание дополнительных потоков внутри кода на C++, который эти запросы обрабатывает. Вы ведь на C++ пишете? Или на питоне обслуживаете этсамое, обоснование необходимости носить маски и сидеть дома, с помощью Машинного Обучения и Искусственного Интеллекта?


C>Код на питоне, так исторически сложилось.


Ну, Cyberax уже написал всё, что он думает. Дескать, пишите свой клиент.

От себя я добавлю — а что будет, если NFS на той стороне начнёт тормозить? Непредсказуемые задержки решаются буфером непредсказуемого размера, а вообще вместо прямой записи в NFS по-хорошему следует взять Apache Kafka, её сломать очень тяжело. Вот пусть она в файлы и пишет, когда сможет.
Re[4]: Пара задач из жизни
От: cppguard  
Дата: 06.12.21 22:29
Оценка:
Здравствуйте, Слава, Вы писали:

С>От себя я добавлю — а что будет, если NFS на той стороне начнёт тормозить? Непредсказуемые задержки решаются буфером непредсказуемого размера, а вообще вместо прямой записи в NFS по-хорошему следует взять Apache Kafka, её сломать очень тяжело. Вот пусть она в файлы и пишет, когда сможет.


Я понимаю, что без знания других других деталей кажется, что ограничения странноваты. На то были свои причины. NFS даёт прозрачность на уровне драйвера файловой системы. Код, который писал в NFS, управлял манипулятором робота и в NFS писал свои логи. Логи нельзя было терять ни на бит, потому что потом по ним восстанавливалась история работы манипулятора и анализировались проблемы. Другой особенностью записи в логи было то, что роботы работали в полях, и единственным транспортом данных с них были флеш накопители, которые хитрым образом ротировались, и когда наступал конец смены очередного сотрудника, он сгребал флешки с логами и мчал из полей домой. Но помимо боевого режима, когда на одном роботе установлено до четырёх манипуляторов, были различные режимы эмуляции: от полностью программной, до частично аппаратной, до режима, когда весь робот потушен, и только манипулятор активен. Чтобы для каждого сценария не выстраивать заглушки и прочее, было решено использовать NFS, потому что тогда можно смонтировать каталог с логами и в tmpfs, и на локальный диск, и вообще везде, для чего существуют драйверы ФС.

P.S. Вот эта особенность, что нельзя прийти и сказать: "А давайте развернём на роботе 100 микросервисов, которые каждый будут тупить и жрать по 1GB, и ещё постоянно падать?" невероятно привлекала лично меня. Потому что во всяких облачных сервисах царит марафон безумия. Я лично видел, как один и тот же сервис переписывался на трёх разных языках под предлогом того, что каждая очередная смена считалась перспективной в плане производительности.
Re: Пара задач из жизни
От: goto Россия  
Дата: 07.12.21 01:32
Оценка:
Здравствуйте, cppguard, Вы писали:

C>1. Имеется API с векторной графикой со всеми обычными функциями: moveTo, lineTo и т.д. На вход подаётся объект типа "холст", угол и шаг. В результате работы алгоритма холст должен быть заштрихован линиями, идущими с заданным шагом и под заданным углом. Шаг произвольный, угол произвольный.


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

В комп. графике в свое время удивляло, что программистские придумки, пусть даже удачные, остроумные, но без особого рокет сайенса с матаном, называют именами тех, кто это опубликовал. Алгоритм Брезенхема, шейдинг Гуро, Фонга... Может, именовали для краткости, референса на конкретный способ.
Re[5]: Пара задач из жизни
От: Слава  
Дата: 07.12.21 11:57
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Код, который писал в NFS, управлял манипулятором робота и в NFS писал свои логи. Логи нельзя было терять ни на бит,

C>P.S. Вот эта особенность, что нельзя прийти и сказать: "А давайте развернём на роботе 100 микросервисов,

Спасибо за подробное пояснение.

Здесь мои знания ограничены, как мне всегда казалось, NFS надёжностью не отличается. Тогда, если хочется надёжных логов, почему нельзя писать в SQLite прямо из процесса, без NFS? Прямо в файлы я бы писать не стал, именно из соображений надёжности хранилища, потому что поломать файл можно сотней разных способов, БД от этого изолирует.

PS: а на Аде у вас пишут? Или не у вас, а у коллег. Потому что робот на питоне — это как-то гм.
Re[6]: Пара задач из жизни
От: cppguard  
Дата: 08.12.21 07:54
Оценка:
Здравствуйте, Слава, Вы писали:

С>Спасибо за подробное пояснение.


С>Здесь мои знания ограничены, как мне всегда казалось, NFS надёжностью не отличается. Тогда, если хочется надёжных логов, почему нельзя писать в SQLite прямо из процесса, без NFS? Прямо в файлы я бы писать не стал, именно из соображений надёжности хранилища, потому что поломать файл можно сотней разных способов, БД от этого изолирует.


Файл поломать невозможно, потому что запись построчная, и даже вылетевший процесс может, максимум, испортить одну строчку. Я не знаю про надёжность NFS, у нас не было случаев порчи данных (при обороте около 1GB/day в течение года), а на сервере физическую ФС можно настроить с нужным уровнем отказоустойчивости. Впрочем, мы писали в ext4 =) SQLite тоже использовалась, но для другого. Сырая запись в файл, всё же, быстрее, и вот, как раз, БД легче испортить, в восстановить невозможно (уже разбирались с этим). Кроме того, контроллер манипулятора был thin client, то есть загружался по сети и не должен был хранить какого-либо состояния, NFS в этом случае снова выручал.

С>PS: а на Аде у вас пишут? Или не у вас, а у коллег. Потому что робот на питоне — это как-то гм.


Питон был выбран техдиректором по принципу "С++ никто не знает, поэтому пишем на питоне, чтобы никто ничего не ломал". Но это не помогло, и переодически робот выдавал курьёзы, которые никто не мог объяснить =) Это был первый в моей жизни опыт работы с роботами, поэтому про остальной рынок сказать не могу. Знаю, что многие плотно сидят на ROS, а это, опять же, Python. Кстати, с питоном легко было добиться квази-детерминированности: сборку мусора мы отключили, за непоявлением циклических зависимостей пристально следили, ввод/вывод за счёт наличия GIL (да-да, того самого) выстраивался в линию. Проблема была только с качеством кода, отсутствием какого-либо статического анализа. Частично эта проблема могла бы решиться за счёт соблюдения жёсткого coding guidelines с активным использованием defensive programming, но ребята на проекте были довольно хиповые и забородили мои идеи в этом направлении.
Re[7]: Пара задач из жизни
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 08.12.21 08:53
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Питон был выбран техдиректором по принципу "С++ никто не знает, поэтому пишем на питоне, чтобы никто ничего не ломал". Но это не помогло, и переодически робот выдавал курьёзы, которые никто не мог объяснить =) Это был первый в моей жизни опыт работы с роботами, поэтому про остальной рынок сказать не могу. Знаю, что многие плотно сидят на ROS, а это, опять же, Python.


В ROS использование Python разве что для прототипирования. Робота написанного на динамически типизируемом языке ты потом устанешь сертифицировать на соответствие очередному заковыристому ISO.
Re[6]: Пара задач из жизни
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 08.12.21 08:55
Оценка:
Здравствуйте, Слава, Вы писали:

С>PS: а на Аде у вас пишут? Или не у вас, а у коллег. Потому что робот на питоне — это как-то гм.


Её вроде в авиации любят. Автомобилестроение любит C++. Робот на Питоне — это просто прототип уровня "купите наш прекрасный стартап".
Re[7]: Пара задач из жизни
От: cppguard  
Дата: 09.12.21 09:08
Оценка:
Здравствуйте, kaa.python, Вы писали:

KP>Её вроде в авиации любят. Автомобилестроение любит C++. Робот на Питоне — это просто прототип уровня "купите наш прекрасный стартап".


И на Python можно написать надёжный код, было бы желание. Но в случае с тем роботом, действительно "купите стартап" =) Кстати, С++ во всяких автопилотах это тоже уровень "пыщь-пыщь, у нас автопилот не хуже теслы!", потому что по-нормальному mission critical пишется на Си или Ада, потом формально верефицируется. Может, конечно, научились делать верификацию С++, но я пока не слышал об этом.
Re[8]: Пара задач из жизни
От: cppguard  
Дата: 09.12.21 09:16
Оценка:
Здравствуйте, kaa.python, Вы писали:

KP>В ROS использование Python разве что для прототипирования. Робота написанного на динамически типизируемом языке ты потом устанешь сертифицировать на соответствие очередному заковыристому ISO.


Формально, да, почти любого робота, который умеет взаимодействовать с внешней средой, нужно сертифицировать, потому что так или иначе робот попадает код какой-то вид оборудования. Но на практике почти никогда не приходится это делать. В моём случае робот собирал урожай с полей и технически его могли записать как обычный трактор, потому что присутствовал HMI в виде джойстика. А автопилот теслы это "всего лишь ADAS, а не автопилот, поэтому идите лесом".

P.S. Когда в США всех погнали ссаными тряпками на самоизоляцию, наш босс сказал, что мы работаем в сельскохозяйственной области, а это essential business, и всех оставили в офисе Вот примерно такой же подход и к сертификации.
Re[8]: Пара задач из жизни
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 09.12.21 11:10
Оценка:
Здравствуйте, cppguard, Вы писали:

C>И на Python можно написать надёжный код, было бы желание.


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

C> Но в случае с тем роботом, действительно "купите стартап" =) Кстати, С++ во всяких автопилотах это тоже уровень "пыщь-пыщь, у нас автопилот не хуже теслы!", потому что по-нормальному mission critical пишется на Си или Ада, потом формально верефицируется. Может, конечно, научились делать верификацию С++, но я пока не слышал об этом.


Mission critical (ASIL D) пишется на C++14, смотри AUTOSAR C++14. Так же есть MISRA C++, но там совсем всё дремучее. Статические анализаторы тоже есть, причем сертифицированные по ISO 26262. Так же стоит учитывать что к mission critical относится очень небольшая часть компонент в машине, основная масса обычный QM, остальная на обычном C++. В теории остальное можно и на Python написать, конечно, но оно ж тырндец падучее и тормознутое будет.
Re[9]: Пара задач из жизни
От: cppguard  
Дата: 09.12.21 16:40
Оценка:
Здравствуйте, 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, тоже связанный с потоковой обработкой данных, в нём все летает, ничего не падает, аптайм исчисляется месяцами
Re[10]: Пара задач из жизни
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 10.12.21 02:31
Оценка:
Здравствуйте, 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++ кода. Магия?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.