Так, заметки на полях..
Запись от CoderHuligan размещена 13.11.2022 в 17:00
Показов 2066
Комментарии 12
Метки tcl
По Tcl несколько позже. Это реальная вещь. Я без проблем подключил звуковой модуль для своей проги, и настроил его. Теперь морзянку строчит как из пулемета.. Но на этом пока все застопорилось и не потому, что я не могу доделать прогу, а потому что как-то руки не доходят это доделать. Но я о другом.. Сложно говорить о сложных для кого-то вещах, но надо. Что мы сейчас имеем в своей основе? Ну, как бы программа делиться на отдельные подпрограммы. Это позволяет разграничить сферы деятельности, ограничить область определения имен, улучшить понимание кода программистами, более легко отлаживать и верифицировать код. Объектная модель лишь продолжила процедурную, как бы навесила на процедурную новый слой абстракций. Но в основе лежит та же процедурщина. Сначала надо бы понять почему мы, вдруг, так вот, взяли и решили поделить программу на более мелкие программы? Говорю "мы" потому что мы все в общем разделяем ответственность перед этим выбором, так как используем это почти каждый день. Для кого-то просто стало удобным взять всё и поделить? Нет, все гораздо глубже. А корни идут от Лиспа и Алгола, которые прямо создавались с прицелом на возможность рекурсивного вызова процедур и функций. Однако были в то время и "отщепенцы", которые явно запрещали это делать, пример - Фортран-77. Рекурсия стала настолько важной вещью в определенных кругах математиков-программистов, что вскоре язык, не позволявший рекурсии начал считаться неполноценным языком. Старые basic подобные языки и язык Forth также не позволяли рекурсию, либо она была сложно реализуема. И вот, теперь, практически все мэйн-стрим языки позволяют это делать, и даже современные бэйсики способны на это. Теперь давайте взглянем сколько процентов в нашем коде занимают рекурсивные вызовы? Практически рекурсия нужна когда нам нужно обойти папки и файлы в системе. В компиляторах она используется для рекурсивного обхода дерева выражений, да и вообще где используются деревья. То есть для каких то узкоспециализированных вещей. В обычном коде она редко или очень редко используется. И чем реже она используется тем лучше, так как: 1. Слишком осложняет понимание кода. 2. Слишком замедляет скорость работы кода. Теперь вернемся к нашим процедурам. Сейчас они реализуются с прицелом на их возможный рекурсивный вызов. Считается, что кто-то, когда-то будет иметь возможность это сделать. Рекурсия же предполагает наличие памяти (стека), которая будет запоминать все локальные переменные в одном кадре (термин, который означает состояние стека в момент работы конкретной репликации процедуры) этого стека. Если процедура вызывает сама себя, то все локальные для неё переменные будут сохранены именно в её собственном кадре. Прошу отметить один немаловажный факт - сохраняются даже те переменные, которые явно не нужно сохранять при рекурсивных вызовах. Просто так проще все реализовать , короче говоря получили универсальное решение. Допустим, перед вызовом самое себя, процедура что-то там вычислит в цикле, но счетчик этого цикла, который уже отработал свое, будет также сохранен в кадре стека.. Конечно это обстоятельство, в некоторых языках, можно обойти, сделав этот счетчик глобальным или статическим для процедуры, но это уже костыли, которых быть не должно. Еще один момент, который нужно отметить: этот стек реализуется аппаратно и в обычных условиях доступ к нему закрыт по причинам безопасности (якобы). И стек этот всегда имеет небольшой размер, поэтому любая глубокая рекурсия может попасть в тупик, что вызовет ошибку периода выполнения. Например сортировка больших массивов при помощи быстрой сортировки часто оказывается невозможной из-за исчерпания стека. А что будет если рекурсия применяется в каком-то очень важном алгоритме, который контролирует работу атомного реактора?. А теперь представим ситуацию, когда программа делится не на подпрограммы, а на блоки кода, которые можно вызывать так же как и процедуры, имеющие свой пул локальных переменных, которые сохраняют свое состояние между её вызовами, а рекурсия могла бы реализовываться путем явного определения стека, если он конечно требуется, который, в свою очередь, мог быть построен на любых принципах: на списках, на массивах и пр. , по желанию самого программиста. При этом мы можем иметь любую глубину стека и сохранять в нем любые переменные - только и только те, которые действительно нужно сохранять.. Можно было бы возразить: так стек экономит память! Нет, не экономит. Предположим крайний случай: имеем три процедуры, первая вызывает вторую, вторая третью. при этом стек будет состоять из трех кадров со всеми локальными переменными. Но тот же объем займут статические локальные переменные. При этом мы получаем высокую скорость работы кода без тормозов, которые накладывает процедурная парадигма. И свободу действий когда стек используется только по своему назначению, а не всегда и везде.. |
Метки tcl
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 12
Комментарии
-
Запись от vantfiles размещена 14.11.2022 в 08:08
-
Запись от vantfiles размещена 14.11.2022 в 08:08
-
Запись от CoderHuligan размещена 14.11.2022 в 12:16
-
Не всегда аппаратно.Запись от politoto размещена 15.11.2022 в 15:36
-
Да. Скриптовые языки часто реализуют его самостоятельно.
Сообщение от politoto
--------
Стековые языки можно улучшить.
К примеру, возьмем Forth. Выражение:
a + d
на нем будет выглядеть как:
a @ b @ +
То есть данное постфиксное выражение "обросло" вот этими значками - собачками, которые означают разыменование адреса переменной, то есть берут адрес со стека и кладут на стек значение по этому адресу.
Если же мы будем класть на стек ТОЛЬКО адреса, то все намного улучшится:
a b +
То есть получили чистое постфиксное выражение!
А как же быть с константами? Просто. Мы используем константу как имя в словаре и при встрече её в тексте кладем на стек её адрес. То есть, к примеру имеем выражение:
7 8 +
"7" и "8" это не числа, а имена этих констант в неком словаре.
Это торкнуло меня совсем на днях.Запись от CoderHuligan размещена 15.11.2022 в 17:08
-
Запись от CoderHuligan размещена 16.11.2022 в 11:59
-
Дорогой Друг! изучайте без скобочный машинный язык низкого уровня " Полиз" (обратная польская запись) берёте программируемый калькулятор с ошибкой при делении 0 на 0 например электроника МК 56 (она лучше, она как п.к. удобна стоит на столе или лежит
клавиши у неё больше чем у других таких забавных вещей) и делайте на ней расчет! хороший удобный язык кстати.Запись от Pokomit_T размещена 30.11.2022 в 14:05
-
Запись от CoderHuligan размещена 30.11.2022 в 15:47
-
Чем это будет отличаться от вызова обычных функций со static переменными внутри? Где будет храниться адрес, куда нам нужно вернуться после вызова этого блока кода? Если блок что-то возвращает в вызывающий, где это будет храниться? Что делать с доступом к этим по умолчанию сохраняющимися между вызовами переменными, если я блок кода буду вызывать в нескольких потоках? Через какую память передавать параметры, чтобы влиять на логику работу блока кода? Как вызвать этот блок из динамической бибилиотеки? Хотелось бы на примере блока кода для printf увидеть что где лежит и где оптимизация.Запись от psergee размещена 01.12.2022 в 14:52
-
Тем, что передача параметров будет не через стек.
Сообщение от psergee
В области памяти, которая зарезервирована под конкретную процедуру. Адрес возврата будет скопирован в ячейку в этой области памяти. Такие свои собственные ячейки имеются у каждой процедуры. Естественно запрещено вызывать самих себя, чтобы не затирать адрес возврата. Программисту можно сделать доступ к этой ячейке, чтобы он мог принудительно подменять адрес возврата.
Сообщение от psergee
А если нам нужна рекурсия и процедуры в выражениях, то у нас на этот случай имеются обычные функции.
Блок-процедура ничего не возвращает. Она лишь может изменять внешние и внутренние переменные, либо непосредственно по значению, либо через ссылки на них.
Сообщение от psergee
В каждом потоке свой экземпляр блока, со своим пулом переменных. Обмен информацией можно производить через известные интерфейсы, например при помощи событий, через глобальные переменные на уровне модуля.
Сообщение от psergee
Значения или адреса переменных кладутся в специально зарезервированные ячейки из пула переменных процедуры, которые видны из-вне процедуры. То есть это является интерфейсом процедуры.
Сообщение от psergee
Через фукции-интерфейсы можно.
Сообщение от psergee
Вот, смотрите. Допустим у нас имеются два вызова printf, и у обоих вызовов один из аргументов одинаков. Если передавать аргументы через стек, то во втором вызове мы будем копировать в стек этот аргумент. Если он будет уже лежать в пуле переменных, то ничего копировать не придется, а вызов printf можно сделать с одним аргументом, так как второй изменять не нужно.
Сообщение от psergee
Запись от CoderHuligan размещена 01.12.2022 в 16:40
-
А выигрыш в чем? Я все так же имею выделенную память, только в области данных, а не в стеке. Только еще кучу проблем с многопоточностью.
Чем это отличается от стека? Тоже область памяти с кадром для конкретного вызова.
Как работающий код узнает адрес обрласти памяти, в которой хранится адрес возврата? Откуда он его возьмет? И что делать, если у меня одновременно два вызова одного и того же блока. Для каждого где-то в куче выделять область под адрес возврата? )
Это ты называешь оптимизацией? Экземпляры блока и всех для каждого потока? Гениально.
Что такое пул переменных и кто конкретно определяет лежит там то же самое или нет? И в чем оптимизация, если на каждый адрес в каждом потоке проверка "а не такой же ли у меня адрес там лежит"?
Что значит с одним аргументом? Код printf'а все равно будет работать со всеми.
Ты так про printf ничего и не описал. Меня интересует конкретно с момента загрузки динамической бибилиотеки в память, что где выделяется и через что передается и возвращается. Где будет твой пул переменных, как я его буду заполнять, как принтф будет его читать. Для простоты уберем терминал, пусть будет sprintf.Запись от psergee размещена 01.12.2022 в 16:59
-
Далась вам эта многопоточность! Ну используйте языки которые на это заточены! кто мешает? Многопоточность надо реализовывать на автоматах, а не аппаратно. И на языках, которые поддерживают создание автоматов.
Тем, что ускоряет программу, так как не надо постоянно пихать в стек psw и другие регистры процессора, а потом их восстанавливать.
Адреса возвратов расставляет компилятор во время компиляции программы в машинный код.
Если не нужно используйте функции в одном экземпляре. Язык должен позволять иметь выбор, что использовать.
У каждой процедуры есть выделенная область статической памяти. Определяет что там лежит сама процедура.
Я ж говорю: не хочешь плодить клонов, имей один экземпляр функции. И все равно с клонами будет быстрее.
Это в Си он будет всегда работать со всеми. А в другом гипотетическом языке, можно работать с любым количеством аргументов.
Компилятор никаких динамических библиотек не загружает, вы что-то путаете. DLL это иная технология и несколько об ином. Меня в данном случае не интересует взаимодействие кода с dll, так как самого кода, как и языка его описывающего еще нет в природе.Запись от CoderHuligan размещена 02.12.2022 в 13:26

Но на этом пока все застопорилось и не потому, что я не могу доделать прогу, а потому что как-то руки не доходят это доделать.
клавиши у неё больше чем у других таких забавных вещей) и делайте на ней расчет! хороший удобный язык кстати.

