• Как написать такой макрос?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, концепция верная. Но мне не хватило документации. Я прошерстил интернет, но не нашёл примеров подобных макросов, а библиотека syn не содержит примеров на такое, хотя и поддерживают Expr::Return. Не могли бы вы привести пример для такого?
    Написано
  • Почему в этом коде значение под указателем перезаписывается?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Произошла какая-то магия, когда я решил вывести на экран в функции создания.
    println!("data fd: {}, must be {fd}", data.fd);
    После этого код внезапно заработал. Я попробовал вместо вывода использовать black_box, я снова поймал ошибку. У меня нет идей, с чем связана эта магия, и такой костыль меня не устраивает. Есть идеи?
    Написано
  • Почему в Rust использую Tokio?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, выше D3lphi написал, что процессор будет занят переключением тредов. Не подтвердилось.
    Написано
  • Почему в Rust использую Tokio?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    D3lphi,
    Спойлер: во втором случае если и удасться их заспавнить, то cpu будет занят лишь одним - переключением контекста с треда на тред.

    Я провёл тест на 20 тысячах соединений. Я подключал 20 тысяч соединений к серверу и бесконечно ждал чтения из них. Я согласен, с тем, что Tokio подходит для этих задач лучше, так как он съел в 20 раз меньше памяти. Но я не согласен с нагрузкой на cpu. В обоих случаях она нулевая после старта.

    Если делать вывод, то Tokio является лучшим решением для обработки миллионов соединений, так как потребляет меньше памяти. Однако производительность Tokio значительно уступает std.
    Написано
  • Почему в Rust использую Tokio?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    D3lphi,
    экономить процессорное время.
    На моих тестах (как и на тех, что я находил в сети) единственное что Tokio делает лучше с точки зрения производительности - это сон. Спит Tokio действительно гораздо дешевле. Если рассмотреть стандартную библиотеку, то она работает далеко не всегда синхронно. Иногда она "паркует" потоки и "будит" их только в момент готовности. Мои тесты подтверждают это теорию.

    Однако я мог не рассмотреть нужный случай. Если есть ещё какой-нибудь тест, где Tokio показывает себя лучше, опишите его. Я проведу его в свободное время.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Everything_is_bad, я с Вами полностью согласен, что и одно ядро может слушать множество портов. Вы были правы. Я вступил с Вами с дискуссию, потому что хотел объяснить для чего мне более одного порта в приложении. Если Вы до сих пор не понимаете, для чего я собираюсь использовать более одного порта, я боюсь, что не смогу Вам это объяснить, так как Вы не понимаете самой проблемы, которую я пытаюсь решить. Если Вам всё ещё интересно, можете поискать информацию в интернете о shared-nothing архитектуре и поискать её реализации (например, SeaStar).
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Everything_is_bad, я не использовал Python дальше школьного курса, поэтому не могу с Вами поспорить. Но не существует других способов решить эту задачу (или через полное деление состояния, даже портов, или нужны примитивы синхронизации). Скорее всего, Python скрывает от Вас эту работу.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Everything_is_bad, если Вам правда интересно, попробуйте в голове быстро представить себе такую ситуацию:
    1 - приложение слушает один порт;
    2 - приложение обрабатывает запросы параллельно;
    3 - вам надо вернуть значение из словаря в ответе.
    Как будете такое реализовать? Если вы знаете способ реализовать это без блокировок и каналов, опишите в двух словах такое решение. Мне будет интересно его почитать.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Saboteur, я именно поэтому и начал вопрос с слов: "Вопрос стоит не в том, способен ли я." Приложение то может, но нет ли потом подводных камней по типу, что его трудно развернуть или что-то подобное. Поскольку никто не предупреждает меня о подобном, я полагаю, что подводных камней всё же нет. Поправьте меня, если они есть.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Drno, вот именно это я и хочу проверить. Если я не забуду, я напишу Вам в ответе результаты теста. Но я бы не ждал этого рано, скорее всего потребуется значительное время для написания такого прототипа и его испытания.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Everything_is_bad, к несчастью гонка за улучшения подходит к концу и ускорять уже почти нечего.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Everything_is_bad, я понимаю Ваше недоумение по этому вопросу, так как не стал описывать Вам контекст. У меня приложение по сути только и делает, что принимает состояние и отдаёт его. Я могу слушать один порт и разбивать состояние на части. Но в таком случае у меня потоки будут "гоняться" за этими частями. Иными словами, при увеличение числа потоков в 2 раза, производительность будет повышаться в меньшее число раз, так как потоки вынуждены "устраивать гонки" за ресурсы. Однако, я могу разбить состояние по числу ядер и отдать каждому ядру свой порт. В таком случае каждый поток работает только с один портом (хотя для одного потока можно выставить и больше, главное чтобы порты были уникальны для каждого потока) и одной частью состояния. В этой схеме у меня нет блокировок, что улучшает способность к масштабированию до почти линейной.
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Drno, я хочу отдать каждому ядру уникальный порт. Это позволит разбить приложение, не используя никаких примитивов синхронизации (в такой системе одному потоку нет смысла взаимодействовать с другим).
    Написано
  • Может ли приложение слушать несколько портов?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Everything_is_bad, связь есть. Можно разбить приложение на низком уровне (я не уверен, можно ли так сделать в питоновском asyncio, поэтому не могу привести понятный вам пример) на n самодостаточных потоков и дать каждому потоку свой порт. Это позволит приложению работать без блокировок и межпроцессорного взаимодействия. Можно слушать и один порт с любым event loop и работать быстро, но в таком случае будут накладные расходы на синхронизацию потоков. Вариант с портом на ядро работает быстрее по той причине, что не требует никаких примитивов синхронизации.
    Написано
  • Куда утекает память в read Rust?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, на Windows эта часть приложения не поддерживается, а именно эта ОС стоит на моём компьютере. В целом, приложение и не разрабатывается для использования на таких тяжёлых ОС, поэтому это не является проблемой для меня.
    Написано
  • Куда утекает память в read Rust?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, попробовал сразу сбрасывать файл. Производительность, очевидно, значительно просела, но и утечка никуда не делась. С профайлером мысль хорошая, попробуй научится профайлить Docker-контейнеры.
    Написано
  • Куда утекает память в read Rust?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, во-первых, у меня есть почти идентичная функция, в которой нет работы с файлами и память не утекает. Во-вторых, я начал заменять части функции (вместо чтения сам заполнил буфер, вернул другой тип, не вызывал блокировки и так далее) и обнаружил, что при комментировании этой строки и её симуляции не происходит утечка.

    Я подумал, что ошибка связана с блокировкой (хотя это тоже странно). Для этого я вызвал блокировку, закомментировал работу с файлом и воспользовался значением из кортежа, чтобы Rust не убрал функцию после компиляции. Утечка всё ещё не произошла. Так как у меня стабильный Rust, я не могу использовать black_box, поэтому не могу выражать уверенность в достоверности этого теста.

    Дальше я заменил работу с файлом на типичный seek и read и посмотрел. Утечка снова появилась!

    Я подумал, что, может, я неправильно симулировал заполнение буфера. Попробовал заполнить более правдоподобно и проверить, что его длина нужного размера. Этот тест тоже не вызвал утечку.

    А дальше у меня закончились идеи, где ещё может прятаться ошибка.
    Написано
  • Куда утекает память в read Rust?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, я попробовал применить ваши изменения. Разницы, ожидаемо, нет. Память утекает где-то в reat_at. Я прошёлся по всем вызовам reat_at, но не нашёл там ничего интересного (4 вызова функций с одинаковыми параметрами, последняя вызывает syscall на unix), но именно там пропадает память.
    Написано
  • Куда утекает память в read Rust?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников, этот код был покрыт тестами ещё давно. Ошибок он ни в Windows, ни в любом Docker-контейнере не содержит. Память утекает не в этой строчке (у меня есть почти идентичный код, только без чтения из файла, и он работает корректно; все тесты успешно сдаются; методом перебора кода построчно было найдено, что ошибка именно в строке "file.read().unwrap().read_at(info.1, &mut buf).expect("failed to read")")
    Написано
  • Куда утекает память в read Rust?

    Eugene-Usachev
    @Eugene-Usachev Автор вопроса
    Василий Банников,
    #[inline(always)]
        pub fn len(&self) -> usize {
            let mut l;
            unsafe {
                // first byte is length
                l = (*self.ptr) as usize | (*self.ptr.offset(1) as usize) << 8;
                if l < 65535 {
                    return l;
                }
                return (*self.ptr.offset(2) as usize) | (*self.ptr.offset(3) as usize) << 8 | (*self.ptr.offset(4) as usize) << 16 | (*self.ptr.offset(5) as usize) << 24;
            }
        }
    Написано