Задать вопрос
  • Как реализуются лицензии по ядрам?

    Vamp
    @Vamp
    определяется лицензия -> макс кол-во ядер и на основании этого создается пул потоков заданного размера
    Так оно и есть.
    Ответ написан
    Комментировать
  • В чём преимущество Clang перед GCC? Что использовать для кросс-компиляции?

    Vamp
    @Vamp
    Зачем Clang использует gcc? Для компиляции?
    Сам компилятор не используется. Только линкер и стандартная библиотека.

    Почему считается, что использовать Clang для (кросс-)компиляции, и в CMake лучше, если он использует тот же gcc?
    Потому что clang строго следует букве стандарта, в отличии от gcc, который трактует стандарт вольно и в целом ориентирован на поддержку экзотических костылей и исторически сложившихся традиций. Поэтому при использовании clang проще писать кроссплатформенный код.
    Ответ написан
    4 комментария
  • Почему INPUT_ENV - null?

    Vamp
    @Vamp
    Чтобы filter_input заработал вместе с INPUT_ENV, нужно в php.ini опцию variables_order добавить букву E

    Советую вместо filter_input брать данные из суперглобального массива $_ENV, а затем фильтровать через filter_var, так как у filter_input есть баг, что не во всех окружениях он работает корректно и всё равно возвращает null. Плюс поведение не соответствует документации - функция возвращает null для несуществующих переменных, хотя согласно документации должна возвращать false.
    Ответ написан
  • Как работать с $_ENV?

    Vamp
    @Vamp
    Как помещать данные в $_ENV: просто заполнить массив или через putenv()?

    Данные туда помещаются автоматически при старте скрипта и при условии, что в php.ini опции variables_order присутствует буква E. Вызов putenv не поместит новый элемент в данный массив, но можно поместить самому напрямую: $_ENV['a'] = 'b';

    почему я при filter_input(INPUT_ENV, 'ЛЮБОЙ_КЛЮЧ_ДАЖЕ_ЕСЛИ_ТАКОЙ_ЕСТЬ') получаю ВСЕГДА - null?

    Это известный баг в php, которому скоро стукнет 15 лет. Я бы рекомендовал пользоваться суперглобальными массивами вместо filter_input.
    Ответ написан
    Комментировать
  • Как использовать разные буферы для чтения и записи в FileChannel и AsynchronousFileChannel?

    Vamp
    @Vamp
    Буфер нужно переключать между режимами чтение/запись:

    FileChannel channel = FileChannel.open(Path.of("test.txtx"),StandardOpenOption.CREATE, 
    				StandardOpenOption.WRITE, StandardOpenOption.READ);
    		
    ByteBuffer buffer = ByteBuffer.allocate(15);
    buffer.put("hello world".getBytes()); // записали в буфер данные
    buffer.flip(); // <--- переключили буфер из режима записи в режим чтения
    channel.write(buffer, 0); // теперь channel.write сможет прочитать записанные в 
                              // буфере данные и записать их в файл
    		
    ByteBuffer buffer2 = ByteBuffer.allocate(15);
    channel.read(buffer2, 0); // channel.read прочитал данные из файла и записал их в буфер
    buffer2.flip(); // <--- переключаем из записи в чтение
    System.out.println(StandardCharsets.UTF_8.decode(buffer2)); // decode читает данные из буфера
                                                                // и составляет из них строку
    
    // Здесь ничего не выводилось, потому что без flip ничего и не записалось в файл.
    System.out.println(new String(buffer2.array())); // ничего не выведет
    Ответ написан
    Комментировать
  • Почему PHP выполняет математические операции неправильно?

    Vamp
    @Vamp
    Потому что типом данных double нет возможности представить число 0.58. Поэтому компьютер берёт наиболее близкое к 0.58 число, которое double может выразить.

    Если вам нужны точные вычисления, то следует воспользоваться специальными функциями:

    $format = bcdiv("580000000", "1000000000", 2); // "0.58"
    
    var_dump(bcmul($format, "100")); // string(2) "58"


    Существует даже специальный сайт, рассказывающий о данной особенности математики чисел с плавающей запятой: https://0.30000000000000004.com/
    Ответ написан
    Комментировать
  • Как ограничить подключение к MongoDB?

    Vamp
    @Vamp
    На уровне ОС это можно сделать через фаервол.
    На уровне базы через настройку authenticationRestrictions в аккаунте пользователя.
    Ответ написан
  • Как пробросить сервер за NAT провайдера?

    Vamp
    @Vamp
    У cloudflare есть решение для этой задачи - cloudflare tunnel.

    Cloudflare Tunnel provides you with a secure way to connect your resources to Cloudflare without a publicly routable IP address. With Tunnel, you do not send traffic to an external IP — instead, a lightweight daemon in your infrastructure (cloudflared) creates outbound-only connections to Cloudflare's global network.
    Ответ написан
    1 комментарий
  • Как исправить проблему с mail php и заголовками для gmail?

    Vamp
    @Vamp
    Заголовки To и Subject подставляются автоматически функцией mail. Вам не нужно добавлять их самостоятельно. Просто удалите строки:

    $headers .= "To: $to\r\n";
    $headers .= "Subject: $subject\r\n";
    Ответ написан
    1 комментарий
  • Как деплоить php приложение вместе с docker?

    Vamp
    @Vamp
    Это типичный вариант развёртывания приложения в докере. Единственный его минус - некоторое время даунтайма между моментом когда опустился старый контейнер и поднялся новый. Для решения этой проблемы есть разные техники. Например, blue-green deployment. Это когда есть два контейнера, условно называемые green и blue. И трафик льётся только на один. Скажем, на green. В момент деплоя обновляется blue контейнер и после того как он полностью будет готов - переключаем трафик на blue. В следующий раз деплой начнётся с обновления green.

    Переключение трафика делается разными способами. Самый безопасный - переписать конфиг nginx и релоаднуть его. Или менее безопасный, зато без необходимости править конфиг, - добавить оба конейнера в одну upstream группу и опустить green контейнер после обновления blue.

    Довольно муторное дело. Но в оркестраторах типа openshift и kubernetes такой деплоймент процесс уже встроен из коробки. Но вот сами оркестраторы довольно тяжелая штука. Для них нужен отдельный выделенный человек, который будет заниматься только ими. Так что я советую начинать присматриваться к оркестраторам только когда количество серваков перевалит за 50. С меньшим количеством это просто нерентабельно.

    Другой вариант развёртывания - контейнер с пхп поднят постоянно, но код проекта монтируется в контейнер через volume. Далее ci джоба по sftp заливает новый код в соседнюю папку и переключает симлинк. Симлинк переключается атомарно и контейнер сразу начинает работать с новым кодом. Ничего больше делать не надо. Я рекомендую такой подход когда на проекте менее 50 серверов.
    Ответ написан
    4 комментария
  • Как работать с DI-контейнером?

    Vamp
    @Vamp
    В самом контейнере задаются только примитивные типы данных?

    В DI контейнере обычно регистрируют объекты, общие для всего приложения, а не для конкретного запроса. Например, коннект к базе, роутер, кеш. Автовайринг примитивных типов в DI - прямая дорога к путанице и сложным для обнаружения ошибкам.

    А все объектные зависимости решаются с помощью автовайринга через Reflection API?

    Можно и так. А можно руками связи выставить. Или аннотациями. Разные способы бывают, смотря какие поддерживаются выбранной вами реализацией DI.

    К примеру, у меня есть контроллер.

    В случае с контроллерами обычно делают front controller, на который сваливаются абсолютно все запросы, а дальше он сам определяет какой из контроллеров нужно создать и передаёт запрос на обработку ему.

    Сам вид принимает шаблоны, это обычные строки с разванием шаблонов, которые нужно подключить.

    Если строки с названием шаблонов фиксированы, хранятся в конфиге/базе и одинаковы для всех страниц и всех пользователей, то можно шаблон и в DI зарегистрировать. В противном случае лучше создавать его во фронт контроллере. Либо зарегистрировать в DI фабрику шаблонов, которая будет создавать объекты вью в зависимости от переданных параметров. Аналогично и с моделью.

    Модель принимает класс соединения с БД, а БД принимает массив с настройками подключения.

    В контейнере можно зарегистрировать объект Settings, в котором хранятся данные для подключения к базе и прочие глобальные настройки, а затем инжектить его в класс для работы с базой. Ещё контейнер может сам выступать хранилищем настроек и инжектить их (в том числе примитивные). Так сделано в DI компоненте Symfony.

    Есть еще класс пагинации, он тоже должен быть в контроллере и его конструктор принимает три параметра типа int.

    Опять же, если эти три параметра не зависят от запроса, то можно зарегистрировать пагинатор в DI. Если зависят, то можно из конструктора перенести эти параметры в метод и вызывать его в контроллере. Например: $page = $this->paginator->calulatePage($one, $two, $three)
    Ответ написан
    2 комментария
  • Как отправить длинное SMS с помощью SMPP?

    Vamp
    @Vamp
    Отправляйте текст через message_payload, а не short_message. В этом случае делением на сегменты будет заниматься провайдер.

    Пример Данилы лучше не использовать. Нельзя втупую резать текст по 153 символа. А ещё там косяк с кодировкой.

    Я не вижу никаких ошибок, потому что либа даже не отправляет мое SMS.

    Дебажить SMPP - это боль и страдания (не зависит от используемого языка). Лучше всего снять дамп трафика и смотреть на сырые пдухи в wireshark. В идеале отправлять смски через другой протокол. Многие провайдеры предоставляют HTTP API.
    Ответ написан
    Комментировать
  • Какой софт поставить на домашний файловый сервер из древнего железа?

    Vamp
    @Vamp
    Я на свой древневековый ноутбук с 32-битным процессором (intel atom) поставил openmediavault. На слабом железе хорошо работает.

    Не верю в стабильность внешних ресурсов.

    А в стабильность хлама значит верите? По опыту эксплуатации хлама скажу, что лучше его выкинуть/продать и взять что-нибудь свежее взамен. Посмотрите мини-пк или одноплатники. Будет надёжнее, меньше места занимать, меньше энергии потреблять. Я в итоге заменил ноутбук на raspberry pi с m.2 модулем, куда вставил терабайтный SSD.
    Ответ написан
  • Какой оптимальный способ попасть в домашнюю сеть снаружи?

    Vamp
    @Vamp
    Самый удобный вариант - развернуть частный VPN типа zerotier или tailscale.
    Ответ написан
  • Как запустить парсер NBBC под PHP8?

    Vamp
    @Vamp
    Нужно ещё конструкторы в классах переименовать в __construct() и тогда останется только два теста, которые заваливаются из-за того, что htmlspecialchars по умолчанию применяет ENT_QUOTES.
    Ответ написан
    Комментировать
  • Низкая скорость отдачи с VPS на конкретный хост?

    Vamp
    @Vamp
    Разница почти наверняка из-за неудачного маршрута PC2->PC1. Маршрут можно посмотреть командой traceroute или mtr (в ubuntu пакет называется mtr-tiny). Далее можно попробовать написать письмо в техподдержку хостера PC2, приложив трейсы (с обоих сторон) и результаты iperf3 (так же с обоих сторон). Тогда хостер может подправить маршрутизацию и скорость восстановится.
    Ответ написан
    5 комментариев
  • Как правильно должно быть развернута инфрастуктура с Docker, Kubernetes?

    Vamp
    @Vamp
    1. Потому что докер объединил уже имеющиеся в линуксе способы изоляции процессов (chroot, cgroups, namespaces) в удобное для использования приложение.

    2. Гипервизором выступает ядро линукса. Поэтому накладные расходы на контейнеризацию значительно ниже, чем на виртуализациию.
    Ответ написан
  • Как избавиться от требования обработки исключения в Project Reactor?

    Vamp
    @Vamp
    неужели есть только один вариант это обрабатывать с поощью try/catch внутри каждого блока что бы избежать Unhandled exceptions?

    Вобщем-то да. Можно вынести try/catch в отдельный универсальный метод, который оборачивает исключение в RuntimeException:

    private @NotNull Mono<JsonObject> invoke(Channel channel, Class<?> clazz, Method method, Object... args) {
        return Mono.fromCallable(() -> clazz.getDeclaredConstructor(Server.class, Channel.class))
            .map(constructor -> ex(() -> constructor.newInstance(this.manager.getServer(), channel)))
            .flatMap(obj -> new GenericData<JsonObject>().invoke(method, obj, args))
            .onErrorResume(Mono::error);
    }
    
    private <T> T ex(Callable<T> code) {
        try {
            return code.call();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    Конкретно в вашем примере можно вызов конструктора переместить в callable, из которого делается Mono, так как из Callable разрешено стрелять проверяемыми исключениями, в отличии от Function, который принимает map:

    private @NotNull Mono<JsonObject> invoke(Channel channel, Class<?> clazz, Method method, Object... args) {
        return Mono.fromCallable(() -> {
                var constructor = clazz.getDeclaredConstructor(Server.class, Channel.class);
                return constructor.newInstance(this.manager.getServer(), channel);
            })
            .flatMap(obj -> new GenericData<JsonObject>().invoke(method, obj, args))
            .onErrorResume(Mono::error);
    }
    Ответ написан
    Комментировать
  • Как правильно добавить точку монтирования в docker compose для elasticsearch?

    Vamp
    @Vamp
    Нужно монтировать /usr/share/elasticsearch/data

    volumes:
          - /home/user/green:/usr/share/elasticsearch/data
    Ответ написан
    Комментировать
  • Как на самом деле работает параллелизм?

    Vamp
    @Vamp
    Вопрос 1. Два конвейера позволяют только сократить накладные расходы на context switch. Параллелизм это не увеличивает, так как вычислительное ядро по-прежнему одно.

    Вопрос 2. Верно. Разделите понятия процесс и поток. Думайте о процессе как о контейнере для потоков, а не как об активной сущности, которая исполняет код. В каждом процессе есть как минимум 1 поток. Все без исключения программы стартуют как однопоточный процесс, который имеет возможность превратиться в многопоточный, заспавнив ещё потоков. Ну и, соответственно, ОС шедулит потоки, а не процессы.

    Вопрос 3. Нет. Процессор сам подгружает инструкции из кеша/основной памяти. Потоки не совершают никаких дополнительных действий для этого. Всё происходит прозрачно для потока.

    Вопрос 4. Kernelspace и userspace потоки отличаются только тем, в каких кольцах они исполняются. Kernel потоки исполняются в привилегированных кольцах, а user потоки в непривилегированных. Во всём остальном эти потоки ничем друг от друга не отличаются. Кольца ограничивают набор процессорных инструкций и системных вызовов, которые поток может использовать. Например, чтение файла с диска - это привилегированная операция (так как требует прямого доступа к девайсу), поэтому когда обычный userspace поток хочет прочитать файл, ОС приостанавливает userspace поток и передаёт управление kernelspace потоку, у которого достаточно привилегий на выполнение данной операции.

    Кооперативную многозадачность можно сделать и самому. Концепция называется green threads. В языках программирования встречается уже готовая реализация грин тредов, только называется иначе: корутины (python), горутины (go), виртуальные потоки (java). Все они делают одно и то же - реализуют кооперативную многозадачность в userspace. При большом желании можно написать и свою реализацию грин тредов без использования уже готовых языковых инструментов. Хотя практического смысла в этом мало (кроме нарабатывания опыта).

    Вопрос 5. Думаю, ответ на этот вопрос очевиден из ответа на предыдущий.

    И всё же под "kernel" обычно подразумевают ядро ОС, а не ядро процессора (которое называют core, а не kernel). Единственный способ запустить поток в kernelspace - написать модуль/драйвер ядра. Обычные программы так не могут.

    Финальный вопрос. Правильно понимаете. Вот только "пошаговая стратегия" - это про многозадачность, а не про параллелизм. Процессор с одним ядром многозадачным быть может. Параллельным - нет.
    Ответ написан
    7 комментариев