Ответы пользователя по тегу Программирование
  • Процессы работают на различных ядрах процессора или нет?

    @Zanak
    Для ОС почти нет принципиальной разницы между процессом и потоком. При создании процесса происходит выделение нового куска памяти, при создании потока - это не обязательно происходит, поток имеет доступ к памяти родителя, процесс нет. Тоесть, в контексте вопроса можно ограничится разговором о потоках.
    Потоков может быть столько, сколько позволяет память, даже на однопроцессорной и одноядерной железке.
    Активность потоков может управляться на нескольких уровнях. Во первых, ОС может в любой момент тормазнуть исполнение потока. Даже если этому и можно помешать, врядли это легко, да и врядли нужно это делать. Среды исполнения, иногда, позволяют указать, сколько потоков запустить для исполнения программы. Например среда исполнения erlang или go позволяет программам создавать не дорогие потоки ОС, на создание которых уходит масса времени, а более легкие, жизненным циклом которых сама среда и управляет. Происходит отображение N потоков программы на M потоков ОС, которые запрашиваются один раз, при старте.
    Поток может находится в одном из состояний: спит - когда планировщик его остановил, активен - когда поток получил управление, заблокирован - когда поток ждет какое - то событие или окончание какого - то действия, например прихода данных по сети, ошибка - когда происходит обработка ошибки или освобождение ресурсов и смерть потока.
    Вопрос оптимальности создания более одного потока/процесса всегда следует рассматривать в контексте конкретной задачи. Даже при неблокирующем обмене данными между потоками, как минимум, переключение потоков, если речь не идет о количестве потоков меньше или равном количеству присутствующих ядер, имеет свою цену по времени. Подозреваю, многопоточная программа начинает выигрывать у однопоточной, когда количество потоков, которым надо исполнятся паралельно не превосходит количество доступных ядер. Как только потоков становится больше, в дело приходится вступать планировщику, и естественно, он работает не мгновенно.
    Вопрос оптимальности архитектуры тоже, на мой взгляд, не имеет общего ответа. Для вычислительных задач может оказаться сравнимо, использовать один двухядерный процессор, или материнку с поддержкой 2 процессоров, а, например, для запуска веб сервера и БД к нему вообще лучшим вариантом может оказаться два независимых компютера.
    Ответ написан
    Комментировать
  • Что случится с программой (Go, Python, JS, PHP), если потребуется выделить память, а оперативная память в ОС закончилась?

    @Zanak
    Ответ на ваш вопрос складывается из ответа на два других:
    - В чем суть работы менеджера виртуальной памяти?
    - Может ли один процесс запросить у менеджера памяти больше, чем процессор в состоянии адресовать, исходя из его архитектуры?
    Ответ на первый вопрос: думаю, обеспечить паралельное исполнение приложений, запущеных ОС. происходит это за счет выгрузки отдельных частей не исполняемых, в данный момент, процессором приложений, чтобы обеспечить потребности активных.
    Ответ на второй: думаю не может. выгрузка страниц на диск все равно подразумевает их возврат в память по тому адресу, откуда страница была свапнута. наличие 2 страниц памяти, относящихся к одному физическому адресу и процессу открывает шанс на потребность их одновременной загрузки, что невозможно.
    Вместо резюме: реакция ОС на "прожорливость" процесса может различаться. У linux есть OOM killer, который прибивает "зажравшиеся" процессы. Форточки позволяют запрашивать память пока место на диске не заканчивается исключительно потому, что работает, обычно, более одного процесса, и каждый из них может занять до максимально адресуемого, для текущей архитектуры, куска виртуальной памяти.
    Ответ написан
    Комментировать
  • Как заполнить эту трассировочную таблицу по псевдокоду?

    @Zanak
    Мы перекладываем элементы из Items в Newitems, при условии, что они прежде не встречались (done = false). Чтобы заполнить требуемую табличку нужно знать содержимое Items, потому что оно может быть и [1, 1, 1, 1], тогда в результате получим NewItems = [1], а может и [1, 2, 3, 4], тогда он будет перенесен целиком.
    И таки да, если я правильно понимаю псевдокод, то ошибок в нем нет.
    Ответ написан
    Комментировать
  • В чем разница multithreading, multiprocessing и асинхронности?

    @Zanak
    Почитал ответы коллег, и решил вставить свои 5 копеек:
    - multiprocessing. каждая задача - это полноценный процесс ОС. процессы могут быть одинаковые, или абсолютно разные. для взаимодействия между процессами используются сокеты (про udp тактично промолчим). сокеты бывают 2 видов, сетевые и unix (юникс сокеты, естественно, присутствуют на юникс системах, под windows возможно присутствует аналогичный механизм IPC, но я не в теме, поэтому не стану сбивать вас с толку). принципиальное отличие для сокетов - это то, что через юникс сокеты взаимодействие возможно только в пределах одной машины, для сетевых сокетов такого ограничения нет.
    - multithreading. главное отличие от процессов - нельзя создать самостоятельный поток, всегда сначала стартует процесс, который это делает. с точки зрения планировщика ОС отличие потоков от процессов весьма небольшое - процессы стартуют каждый в своем адресном пространстве, со своим стеком и дескрипторами. все потоки, делят адресное пространство с родителем и другими потоками. из плюсов - взаимодействие между потоками максимально быстрое, его возможности ограничены только фантазией автора программы. из минусов - взаимодействие между потоками возможно только в рамках одной программы, взаимодействие со внешним миром не отличается от случая множества процессов, из за того, что все данные доступны всем потокам сразу, приходится использовать специальные техники программирования с участием блокировок.
    - асинхрон. асинхронное програмирование - это есть ни что иное, как кооперативная многозадачность. всегда есть диспетчер, который умеет переключать асинхронные задачи. в некоторых новомодных языках, вроде go, компилятор неявно вставляет вызовы диспетчера, чтобы горутины могли исполнятся паралельно. в языках, где поддержка асинхронности появилась позже, чем сам язык приходится в явном виде указывать вызываем мы синхронный или асинхронный код. при вызове асинхронного кода происходит вызов планировщика, который добавляет запрошенную функцию в очередь и производит переключение на другую задачу. иногда приходится в явном виде обращаться к диспетчеру, если, например, наша асинхронная задача будет исполняться заведомо долго.
    Ответ написан
    Комментировать
  • Есть ли какойто подход к программированию называемый Api First?

    @Zanak
    Такое возможно, если речь о сервисах. Пишете спеку для swagger-а, с помощью их тула генерируете болванку сервиса, допиливаете реализацию в ручную (я не помню, генератор заполняет обработчики кодом, или оставляет их пустыми). Правда это работает только при создании сервиса с нуля, поддерживать существующий код вам все равно придется руками :)
    Для приложений первичны, скорее всего, данные, с которыми вы работаете, чем методы их использования. Поэтому, для приложений, такой подход к разработке лучше не использовать, как мне кажется.
    Ответ написан
    Комментировать
  • Как сделать имена переменных (полей) более читаемыми?

    @Zanak
    Если вопрос еще актуален: не делайте то, что вы описывали в водной части вопроса. Включение отношений объектов в их именование - это есть плохая идея, потому что рефакторинг иерархии классов может привести, при таком подходе к именованию, к изменению имен и содержимого методов, напрямую этим рефакторингом незатронутых. Это особо актуально в случае скриптовых языков, где модули могут подгружаться в процессе исполнения, и импорт библиотеки происходит ни при каждом запуске приложения. Хорошо если вы тщательно покрываете свой код тестами, но даже они могут не спасти.
    Для именования таблиц лучше использовать имена существительные английского языка в единственном числе. Для удобства, можно соединять несколько слов с помощью символа '_'. Например: user, user_profile, user_acl, для хранения учетки пользователя, его профиля и прав соответственно. Если вы расширяете чужой проект, допустимо использовать префикс, чтобы визуально контролировать, какие таблицы добавили вы, а какие существовали изначально: например - my_user_additional_info. Такой подход в достаточной мере самодокументирует ваш проект и упрощает вашим возможным коллегам его поддержку.
    С именованием классов и переменных подход похожий. camelCase или snake_case, или даже PascalCase, это дело вкуса, по большому счету. Да, у многих, если не всех, языков есть свой стиль форматирования кода, но следовать ему или нет, это ваш выбор. Я ограничусь советом: придерживайтесь выбранного стиля оформления текста, хотя бы до конца проекта.
    Ответ написан
    1 комментарий
  • Циклы. While, do while, for, чем отличаются?

    @Zanak
    Как - то, почитал я ответы коллег, и остался разочарован. Понятно, что вопрос не простой, а очень простой, но можно и по аккуратнее в изложении. В общем, мои 5 копеек.
    Любой цикл - это кусок кода, который обычно называют телом цикла, и который мы желаем выполнить несколько раз. Количество повторений может быть заданно заранее, например: цикл от 0 до 10, зависеть от данных, например: для каждого элемента массива или зависеть от значения, которое мы в теле цикла вычисляем, например: пока f(x) > 0 выполнять. По крайней мере, во всех известных мне языках программирования, есть оператор досрочного выхода из цикла.
    while. Цикл с предварительным условием. Выполняется пока условие истинно. Проверка происходит до исполнения тела цикла. Если условие изначально ложно, то тело не выполнится ни разу. Если условие ни когда не станет ложным, то мы получим бесконечный цикл. Распространенные ошибки новичков, при использовании этого цикла:
    - условие не зависит от переменных, которые изменяются в теле цикла, и оно всегда получается истинным
    - условие ни когда не станет ложным, в силу его свойств, например: X * X >= 0 всегда верно
    Пример на php:
    $i = 1;
    while ($i <= 10) {
        echo $i;
        $i++;
    }

    do ... while. Цикл с постусловием. Отличие от предыдущего в том, что тело цикла исполняется хотя бы один раз, и после этого происходит проверка условия выхода из цикла. К типичным ошибкам предыдущего вида циклов добавляется то, что этот цикл гарантированно исполняется один раз, что не всегда желательно.
    В этом примере цикл отработает один раз, не смотря на то, что условие ложно:
    $i = 0;
    do {
        echo $i;
    } while ($i > 0);

    for. Чаще всего этот оператор описывает цикл с фиксированным количеством повторений. Вот так он может выглядеть, например, для php:
    for ($i = 1; $i <= 10; $i++) {
        echo $i;
    }

    но есть языки, где этот - же оператор используется для описания цикла, перебирающего множество значений, например элементы массива. К возможным подводным камням этого вида циклов следует отнести порчу значения счетчика итераций. Изменять его, например для досрочного выхода из цикла, считается плохим стилем программирования, и в особо тяжелых случаях может приводить к трудно диагностируемым ошибкам.
    Ответ написан
    Комментировать
  • Как создавать объект с большим количеством свойств?

    @Zanak
    Я бы разбил задачу на 2 части: создание объекта и его использование.
    Создание объекта:
    - Кроме обязательных, могут быть условно обязательные (это в случае, когда задание одного параметра делает обязательным еще какое - то количество параметров) и опциональные.
    - Когда все параметры обязательны, то пишем конструктор.
    - Инициализацию условно обязательных параметров может иметь смысл обернуть вспомогательным классом, который можно сделать доступным только в контексте основного класса, и в его реализацию включить проверку переданных параметров.
    - Постройку классов с условно обязательными и опциональными параметрами, кроме прямого разбора параметров, можно реализовать с помощью фабрик, которые будут содержать меньшее число параметров, и устанавливать опущенные в корректные значения по умолчанию.
    - Вместо фабрики можно скрыть ваш класс за фасадом с более простым интерфейсом.
    - Так же, можно создать несколько методов постройки объекта, а конструктор реализовать в виде диспетчера, который вызовет нужный, в зависимости от переданных параметров.
    Использование объетов:
    - Для условно обязательных параметров не избежать создания методов, которые принимают весь кортеж связанных между собой параметров. Это вместо отдельных сеттеров для каждого свойства.
    - Кроме set/get методов доступа можно использовать прямой доступ к свойствам, всем или некоторым, особенно, если есть взаимная зависимость параметров, и создания полноценного валидатора для всего набора параметров конструктора не избежать.

    Если отвечать наиболее обще, то я бы поступил как - то так.
    Ответ написан
    Комментировать
  • Должны ли переменные окружения удаляться после завершения сеанса?

    @Zanak
    Каждый процесс в системе получает набор переменных окружения от своего предка.
    Исходные значения, которые получают процессы стартующие сразу после загрузки ОС задаются в свойствах системы, если речь про windows, или файле конфигурации, если мы говорим о unix like системе.
    Кроме общесистемных настроек переменных окружения, есть еще пользовательские переменные, которые в windows настраиваются рядом с системными переменными, а в unix есть варианты, но скорее всего это будет .bashrc в домашнем каталоге пользователя, если говорить о linux и его bash shell. Пользовательские настройки читаются процессом, выполняющим авторизацию пользователя, перед тем, как запустить его командную оболочку. Когда пользователь наконец получает возможность начать работать с компом, он получает объединенный набор переменных окружения.
    Все процессы, которые порождает пользователь, получают его версию переменных окружения. Если процесс программно изменяет любое значение, то это действует только для этого процесса, и всех процессов, которые он породит после.
    А теперь ответ на ваш вопрос. :) Если вы изменяли настройки только в памяти, то и действовали они, пока был жив процесс, для которого вы это делали. Завершили процесс непосредственно, или вышли из системы и вошли вновь - начинайте заново.
    Ответ написан
    Комментировать
  • Зависит ли оптимизация программ от языков программирования?

    @Zanak
    Давайте по порядку:
    1. Что такое оптимизация программы?
    Есть такое понятие, как алгоритмическая оптимизация. В простых случаях - это, например, вынос присваивания неизменяемого в цикле значения за его рамки, сохранение промежуточных результатов вычислений, при обработке сложного выражения, развертывание цикла, да и много чего еще, что умеют делать современные компилеры с исходниками. Другое дело, что это, в той или иной мере стараются делать все языки, и скриптовые, и компилируемые, ну, может быть кроме асма, там что напишеш, то и получешь, на сколько мне известно.
    Кроме оптимизации алгоритмической, есть еще оптимизация под целевую платформу. Компилируемые в нативный код процессора языки стараются эту оптимизацию делать, но, на сколько глубоко, скорее всего зависит от конкретного языка. Например Цэ может вылизать каждый байт результата компиляции, а Go приходится помнить и про сборщик мусора, и про планировщик горутин, кроме собственно оптимизации целевого кода. Для скриптовых языков об этой оптимизации можно говорить только в случае поддержки ими jit компиляции, что есть не у всех из них.
    2. Деление на высокоуровневые и низкоуровневые языки достаточно условно.
    Первй критерий, который припоминается - это возможность работы с железом напрямую. Во времена DOS это были асм и цэ, хотя, смутно припоминается, что и паскаль и даже бейсик позволяли скинуть значение в порт или прочитать его. Сейчас, в большинстве случаев, ОС работает в защищенном режиме, и пользовательское приложение прямого доступа к железу не имеет. Особняком стоят языки, которые умеют порождать код, стартующий на голом железе, и здесь кроме асма и це можно, к примеру, вспомнить про erlang, который, хоть и скриптовой, но вроде как умеет стартовать без присутствия ОС, ну или новомодный раст, тоже достойный вариант для рассмотреия.
    3. Отличия между языками - это прежде всего по задачам, для которых они предназначены. Например, большинство языков имеет ограниченную точность математики, и для проведения высокоточных расчетов приходится привлекать внешние библиотеки, но есть фортран, который изначально создавался для проведения расчетов, и он прекрасно справляется с этим сам. Другой пример, на асме можно написать текстовый редактор, только это будет долго по времени, в отличии, того же Цэ с плюсами, но если речь зайдет про отладчик программ, то здесь без асма ни как. Ну и на последок, Lua, который популярен у разработчиков игр как встраиваемый в платформу язык, благодаря своей достаточной скорости при небольшом размере среды исполнения.

    Про джаву ни чего сказать не могу, потому как знаком с ней только по продукции jetbrains и на примере эклипса или нетбинса.
    Ответ написан
    Комментировать
  • Особенности рантайма (любой язык)?

    @Zanak
    1. Ответ на ваш вопрос специфичен для конкретного языка. Например Цэ, на сколько я знаю, не несет дополнительного оверхеада во время выполнения, в то время как golang имеет свой рантайм, что связано с управлением памятью и поддержкой специфичных для языка возможностей. У скриптовых языков рантайм еще более тяжел, и потому они они дольше стартуют, даже если далее подключается jit компиляция и полезная нагрузка исполняется бодро.
    2 + 3. В подавляющем большинстве ответ нет, заменить загруженную в память программу нельзя. Erlang вроде как умеет штатно, но и там это высший пилотаж.
    Ответ написан
    Комментировать