Pull to refresh

Comments 196

Некоторым языкам программирования десятки лет 

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

Это нативная реклама Rust! Настолько нативная, что сразу и не поймешь,

но иначе и быть не может!

Rust'у через два года будут десятки лет. Целых два десятка.

Конечно же ему будет... 10, через год, мы же от "дня рождения" (то есть, релиза 1.0) будем считать, а не от момента "зачатия"? :) Вроде бы Грейдон Хор к Восточноазиатскому региону отношения не имеет и логично использовать европейский подход к расчету возраста. Так что пока еще Rust только 9 годиков, совсем маленький.

А сколько лет таблице умножения и подумать страшно…

"Большенству"? Грамотей.

А уж сколько лет орфографическому словарю...

Fortran - 1957

COBOL - 1959

LISP - 1960 - незаслуженно обижен

PL/I - 1964

APL - 1966

C - 1972 - но его почему-то нет в обзоре

Ada - 1980 году - а эта молодая дама есть

C++ - 1984 - всё что дальше - видимо совсем ньюфаги и им не место в обзоре

RPG - 1959. До сих пор поддерживается.

BASIC - 1964

Позор на мою голову... Как я мог забыть BASIC?!

Я думал еще Forth добавить (1971). Но уж очень он специфичен )

Shell script (тот самый, который получил дальнейшее развитие в bash и прочих подобных оболочках) - 1977

спасибо за этот коммент, даже в карму плюсанул. Вот почему так часто забывают про этот замечательный язык программирования, shell??
Да, он достаточно специфичный, но всё же на нём можно писать (и пишутся) полноценные немаленькие программы.

Shell довольно выразительный язык, если на нем аккуратно писать. Когда-то половина git была реализована в таком стиле. С другой стороны, на нем пишет много людей, для которых программирование не является основным видом деятельности.

А зря. Может с практической точки зрения он и правда очень специфичен, но с точки зрения изучения языков программирования форт-машина даст фору много кому.

Я имел в виду, что Forth не столько язык программирования, сколько виртуальная машина со своим языком, причем неограниченно расширяемым.

с точки зрения изучения языков программирования форт-машина даст фору много кому

А вот с этим безусловно согласен.

Форт до сих пор во всяких модных заменах BIOS используется, из массового современного, ЕМНИП, загрузчик Apple, например.

Как я мог забыть BASIC?!

Хорошо, а Pascal (1970), который явно наследовал Алголу-60?

Паскаль наследовал, в чём-то - обоим Алголам, и 68му.

А Ада - точно наследовала Паскалю, где-то встречал даже утверждение, что это - более современный и продвинутый вариант Паскаля.

Вряд ли это верно. Паскаль того времени задумывался как очень компактный язык, а Ада имеет монструозный синтаксис и семантику.

Ada выглядит как «максимальный Pascal», но с учётом того, что Pascal в своём исходном виде — это по сути Algol-60, в который добавлены средства минимально необходимые для работы с нечисловыми данными, стоит ли считать Аду «дочерью» или «сестрой» [двоюродной?] Паскаля ясен не до конца.

Ada выглядит как «максимальный Pascal»

В 1990 году во всесоюзном издательстве "Финансы и статистика" вышла
книга "От Паскаля к Аде", участие в подготовке которой принимал и я:

От Паскаля к Аде/ Т.Ю.Бардинова, В.Ю.Блажнов, А.А.Маслов, В.Н.Орлов. — 1990 Москва, Финансы и статистика, 1990. 255 с. Твердый переплет.

В книге рассматриваются основные приемы программирования на
языках Паскаль и Ада. Изложение материала сопровождается большим
количеством примеров программ, иллюстрирующих аналогичные возможности обоих языков программирования.

Одна из первых книг по языку программирования ADA/АДА в Советском Союзе и приятно сознавать, что оба языка всё еще живы.

Было описание стандарта языка, в чёрном переплёте с тиснением на обложке "язык Ада".

По сию помню, как крестились бабка с дедом на нижних полках плацкарты, когда я, лёжа сверху принимался читать стандарт..

;)

У меня котэ как раз интересовался, что бы можно было почитать о языке Ада.

Принюхивается к Джехани.

Джехани и две нижних у меня есть, и одну из них я читал. Но тренироваться негде было. А жаль, язык мне нравился

О, в старшие школьные годы у меня была книга Перминова. Как раз, когда я скупал почти всё по программированию, что попадалось на глаза. Даже не зная толком языка (только изучал Паскаль), я нашёл там много интересного.

PL/SQL = Ada + SQL

В ТЗ от американской военщины на разработку Ады было прямо сказано "за основу берем паскаль". Так что считать Аду его дочерью вполне корректно.

В самом ТЗ от военщины ничего такого не было, поскольку там с Адой на конкурсе точно соревновался PL/I и, вроде, ещё Алгол-68, которые производными Паскаля безусловно не являются.

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

Далее в лучших традициях военщины работало три независимых команды, а по конкурсу как раз отобрали финальный вариант.

Я просто недавно в букинистическом прихватил книжку Вегнер П. "Программирование на языке Ада"

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

До ее разработки рассмотрели существующие языки, решили что ни один не подходит,

И всё заверте...

Тогда и Pascal - 1970 (извините, выше уже было...)
Но серьёзных вещей на нём я не встречал...

Если считать Delphi за паскаль, то на нем было написано много интересного: сам Delphi и C++ Builder, Total Commander, первые версии Skype, The Bat!, IDA pro, Altium Designer и много еще чего.

На Паскале (в т.ч. Турбо Паскаль, Делфи и пр.) написано огромное количество программ. Я и сам когда-то в прошлом веке по своей работе на Турбо Паскале написал большое количество обучающих и экспертных программ по разным дисциплинам (я работал вплотную с преподавателями вуза), кот. в т.ч. распространялись по вузам через Фонд алгоритмов и программ. Вообще во времена ДОС на Борланд Турбо Паскале было написано очень большое количество программ (коммерческих, бесплатных и условно-бесплатных), имевших характерный интерфейс от библиотеки Турбо Вижн. А на Делфи написано сколько программ, в т.ч. как распространяемых (платных и бесплатных), так и для внутреннего использования на предприятиях и в организациях (в т.ч. больших проектов). Нашел вот с ходу статью: Все известные программы на Delphi (хотя и этот список - не полный).

С одной стороны -да - тот эмулятор табуляторов что был в 59-м и совре менный Full Free ILE RPG (RPGLE) выглядят как два разных языка. И при этом чуть не каждый новый TR (Technology Refresh - минорное обновление системы) для IBM i (а их по 2-3 в год выходит) содержит что-то новое и в языке тоже (где-то в последнем вот dcl-enum появился)... И да, более 80% кода на этой платформе пишется на нем.

С дугой стороны, все попыткивынести язык за предлы платформы (тот же VisualRPG) особого успеха не имели - слишком глубоко он в нее интегрирован и слишком тесно связан с интегрированной в платформу БД DB2...

Ага за LISP прям обидно.
к сожалению в я так и не собрался его изучить во время моего недолгого заигрывания с програмированием в начале 90х, но хотел, вот честное слово )

До Lisp надо дорасти) Вообще, это самый, наверное, развитый из всех современных языков, все эти 60 лет он непрерывно совершенствовался.

Prolog - 1972

SQL - 1974

Ну SQL это не ЯП)

Как минимум симейство. (как максимум вообше не ЯП, т.к. он хоть и тьюринг-полны, но во первых не сразу, в вторых ну камон, это не ЯП)

Т.е. тогда Lisp надо вспоминать с вполне современным Clojure

SQL это не ЯП

Это именно ЯП, но не императивный, а декларативный. ProLog и LISP - тоже декларативные языки.

Тут вечная путаница. Часто SQL называют процедурные языки, такие как T-SQL (MS SQL), PL/SQL (Oracle), plpgsql (PostgreSQL), SQL PL (DB2) и т.п., которые являются полноценными языками программирования.

С выходом ANSI SQL/PSM грань между декларативным и процедурным SQL оказалась вообще размыта.

SQL по этой классификации компьютерных языков относится к Query Language, а Programming Language живут на соседней ветке.

Сюда загляните https://en.wikipedia.org/wiki/Declarative_programming

declarative programming is a programming paradigm—a style of building the structure and elements of computer programs—that expresses the logic of a computation without describing its control flow.

...

Common declarative languages include those of database query languages (e.g., SQL, XQuery), regular expressions, logic programming (e.g. Prolog, Datalog, answer set programming), functional programming, and configuration management systems.

Это было до 2003. С закреплением ANSI SQL/PSM в стандарте ISO/IEC 9075-4:2003 SQL официально получил поддержку процедурного программирования и перестал быть чисто декларативным.

SQL - 1974

Причём PL/SQL = SQL + Ada

У меня на балконе до сих пор где-то лежат пожелтевшие рулоны с распечаткой описания PL/1 и всяких его утилит. Раньше их использовал для накрывания стола под пиво с друзьями и кретками. Было прикольно читать между глотками)

Абидна, почему забыли про

ALGOL - 1958

Я на нём писал свои первые программы.

Алгол разве жив? Его нишу целиком занял Паскаль, созданный как учебный язык, который следовало учить перед переходом на Алгол.

PS Бейсик был создан как учебный язык, который следовало учить перед переходом на Фортран, но вытеснить Фортран не смог.

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

нет, ассемблер это язык программирования. А "не в том смысле в котором мы понимаем сейчас", это просто забытые термины низкоуровневый и высокоуровневый.

Только исторически. Язык - это лексика, синтаксис, семантика. У всех трансляторов ассемблера все эти составляющие очень разные.

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

Кстати, вопрос на засыпку: CIL и Java bytecode — это языки какого уровня? По той самой архаичной классификации это всё языки высокого уровня. И даже более того, уровень абстракции у них выше, чем у C, потому что они отвязаны от железа и поддерживают ООП.

java bytecode это не язык программирования. Тем более что как минимум два (java/kotlin), а то и больше языков умеют в него транслировать.

В прошлом, ассемблер мог условно компилироваться под разные архитектуры (ну очень дружественные правда), и то, просто приходилось много править. Отсюда собственно и появилось желание написать С, как язык, который гораздо меньше нужно править для компиляции под разные архитектуры.

Но ассемблер - это полноценный язык программирования. С семантикой, с условиями. И макросы есть.

И всё-таки, машинный код считается точно таким же языком программирования, как ассемблер. Он и называется формально - машинный язык. Но и то и другое - это не язык сам по себе, это прямое представление конкретной машинной архитектуры в различной форме разной степени читаемости. Условия и макросы есть не в каждом ассемблере, и собственно то, что отличает ассемблер от машинного кода - оно в каждом ассемблере разное. Поэтому сейчас не говорят - язык ассемблера, говорят - группа языков ассемблера. Потому что почти каждый ассемблер - это отдельный язык. Даже элементарно, мнемоники для одной и той же архитектуры могут быть совершенно разные. Процессор один, язык ассемблера один, бинарный выход один, а текст программы совершенно другой.

В контексте темы суть моего замечания в том, что ассемблер жив (на нём пишут) и поныне, но давно не живы те изначальные ассемблеры для множества архитектур, типа ассемблера 1947 года для ARC2.

И всё-таки, машинный код считается точно таким же языком программирования, как ассемблер. Он и называется формально - машинный язык.

В общепринятой терминологии, языки предназначены для людей (писать, читать, общаться, понимать), а для машин - коды (здесь же opcode, bytecode и т.п). Computer language, Machine code .

Языки программирования это подвид компьютерных языков (кроме них здесь языки описания конфигураций, разметки, представления данных и ещё ряд других)

Иногда говорят '"машинные языки" вместо "машинные коды", но это либо литературное украшательство, либо просторечие. Коды люди тоже могут воспринимать, но это не типично. В "Матрице" этот момент колоритно показали.

Загляните в ГОСТ 19781—90, например. Машинный язык и язык ассемблера в определениях есть, машинного кода нет.

Честно говоря, тот факт, что они все назвали языками выглядит как очередной местный терминологический нюанс. Возможно - переводческий, или начитались фантастики, где машины могут общаться на своих языках. Может по стоянию на годы разработки этих ГОСТов с определениями ещё толком не разобрались, все же процитированная Wiki отражает уже современную картину. В любом случае, из-за этого в голове потом возникают лишние ассоциации, которые ведут к неправильным выводам. Русский технический в этом отношении крайне сложный и запутанный язык.

Возможно - переводческий, или начитались фантастики, где машины могут общаться на своих языках.

Человек "общается" с машиной на ее языке. "Машинный язык" - тот который "понимает" машина. "Код" - это что-то требующее трансляции, по определению. Не такой однозначный вопрос с терминологией. Перфокарта - однозначно на машинном языке. А запись команд в hex-формате на бумажке, это код, который нужно переводить в двоичный. Возможно так считали инженеры в то время.

Код" - это что-то требующее трансляции, по определению

Трансляции во что?

В команды процессора. Или в слова русского языка. В то, что "закодировано кодами".

А чем представлены команды процессора если не кодами?

инструкции процессора, коды инструкций.
И команды ассемблера.

Вы бы ещё древнеегипетские манускрипты в качестве аргументации предложили...

Это действующий стандарт.

увы...

Но и то и другое - это не язык сам по себе

Так вы уже определитесь, это языки программирования или не языки программирования.
Есть формальная терминология, из которой ассемблер - язык программирования, машинный код - язык машины.
То что писать можно на языке машины, так и на брейнфаке можно программировать и на МК52, и на ЧПУ.

java bytecode это не язык программирования

Зато у CIL слово "language" прямо в названии, да и ассемблер для него есть (ilasm). Можно писать на C#, а можно прямо в IL.

На мой взгляд, CIL, так же как LLVM IR, P-code или даже TIMI, все же ассемблер, хоть и гипотетического процессора. Технически, вполне можно спроектировать CPU для которого это будет машинным кодом.

Компьютерные языки вообще и языки программирования в частности это языки на которых пишут люди - программисты.

Машинные коды это компактное представление программы, которое предназначено для чтения машиной, а не человеком.

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

Представление машинного кода в человеко-читаемом виде — это ассемблерный листинг.

Но не забывайте, что тзначально ассемблер — это инструмент, программа, которая из человеком написанного текста генерирует программу (машинный код + сырые бинарные данные).

И соответственно, раз был (есть) ассемблер, был (остается) и язык ассемблера.

И в этом языке помимо представления машкода в виде мнемоник, как вы выразились, были и control structures, которые априори не имели никакого представления/воплощения в машинном коде.

Например, директива .org, которая диктует ассемблеру, какой адрес будет иметь данное место программы, что необходимо для правильного вычисления абсолютных (а иногда и относительных) адресов.

Например это db, dw, dd, которые уж точно не соответствуют никаким инструкциям процессора.

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

Опять же, макросы, .if/.endif, комментарии, процедуры.

Так что вы не совсем правы.

Есть ассемблерный листинг, например, который может быть выхлопом дизассемблера. И он, да, чисто представление машинного кода. Но есть, все таки язык ассемблера, которые шире одного лишь множества человеко-читаемых представлений машинных инструкций.

"Ассемблер?" )))

Ну, тогда и сам машинный код тоже можно объявить языком. В одном буквенными символами записываем инструкции, в другом -- цифровыми.

Машинный код формально называется машинным языком, было раньше такое определение. И в этом разница, язык, который просто наследуется из архитектуры системы (определение языка - транзисторная схема), и язык, который сконструирован в виде независимого ни от чего набора правил.

MOVB R5, (R1)+

110521

Одно и то же, но разными словами языками.

Мне кажется, что вы ошибаетесь. Команда к примеру с переменной Numeric++ тоже имеет при компиллирование 1:1 эквивалент в ассемблере и в машинном коде. От этого с++ не перестаёт быть языком. Постоянно будут возникать новые языки, под капотом которых будут языки предыдущих поколений. Хороший пример JavaScript или Phyton.

Достаточно опрометчиво делать вывод о том, ошибаюсь ли я, не поняв предварительно, что я, собственно, сказал.

Numeric++ может иметь множество разных эквивалентов в ассемблере и в машинном коде, в зависимости от того, где лежит этот самый Numeric. А куда его положить будет решать не программист, а компилятор, и зависеть это будет не только от операции Numeric++, но и от других операций с Numeric.

Э-э-э... Вообще-то, JCL вовсе не часть PL/1 :)

Вот да, JCL, конечно, не совсем язык программирования, но стар, и очень много использовался с IBM/ЕС... //GO SYSIN DD *

:-)))

Да, автор разбирался что ли? Копипастнул листинги целиком, не вникая.

Очевидно, взяли что первое под руку попалось. Например, приведённый код на Ada состоит из функции-обёртки, внутри которой ассемблерная вставка. Очень идиоматичный код, ничего не скажешь.

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

Согласен. Программирование в 70-х и 80-х было магичнее, душевнее и удовлетворённестней. ))

А, ща... Замучался копайлотовские поделки за мамкиными программистами править.

Думается, тут как везде. Общая тенденция - как можно быстрее выбросить продукт на рынок. Кривой, косой - не важно. Главное - быстрее место застолбить. Баги будем править потом.

Естественно, что такие требования диктуют соответствующие подходы к разработке.

Исключение составляют нишевые отрасли где цена ошибки очень высока. И там сохраняются "ретро" подходы - высокие требования к эффективности и надежности продукта прежде всего. Всесторонне тестирование (включая нагрузочное) занимает в разы больше времени чем сама разработка.

Где это может быть? Наверняка в управлении разного рода производственными процессами. На уровне центральных серверов банков. Ну и подобные вещи. Там все достаточно консервативно.

Я вот в банке. Центральные сервера на IBM i. С одной стороны - платформа развивается (примерно раз в пару лет новая версия, пару раз в год - TR - минорное обновление версии). С другой - вполне себе ретро по идеологии. Никаких тебе докеров с кубернетисами, никаких фреймворков. Многопользовательская система, работа в рамках изолированных заданий (job). Работа с сервером через эмулятор терминала IBM5250. Невольно вспоминаются советские БЭСМ-6 или Эльбрус :-)

Основной язык - RPG. Хоть и уходит истоками в 1959-й год (тут уже упоминался), до сих пор развивается. В настоящее время нормальный процедурный язык. Сейчас уже есть и автоматические массивы (как с автоматическим, так и с ручным управлением выделением памяти), overload процедур (несколько процедур с одинаковым типом возвращаемого значения но разным набором параметров могут быть объединены под одним именем - компилятор сам разберется какую именно вызвать в том или ином месте).

При достаточно простом синтаксисе (современный содержит "легкое послевкусие" от PL/I) содержит много "сахара" (особенно при работе со структурами данных).

Отсутствуют UB.

Отсутствует как класс понятие "неинициализированная переменная" - любая переменная всегда инициализируется дефолтным для ее типа значением (если явно не указано иное значение инициализации).

В целом для работы с БД и обработки разной коммерческой информации очень удобный и эффективный язык.

Где это может быть? Наверняка в управлении разного рода производственными процессами.

Это просто Вам повезло не видеть код, который иногда работает в АСУТП. Особенно когда это пишется не профессиональными программистами, а технологами - "а чо такого, нафига тут программист, всякие языки IEC 61131-3 для них же (технологов) и создавались"

До сих пор метеорологические и синоптические модели написаны на Fortran, Помню на кафедре в 2000 году пытались их переписать на другие языки (вроде на Pascal). Как закончилась пандемия встречались. Сейчас переписывают на Python. Всё идёт дальше всё меняется.

Надо было на Си переписывать.

Получилось бы раз и навсегда. ;-)

Сами ядра вряд ли когда-нибудь будут на питоне. Скорее всего пишут обертки на питоне для модулей, написанных на фортране.

Некоторым?
Perl, PHP, C#, Java, Javascript - языки которым более 20 лет.

Perl5 в этом году 30 лет будет)

Да и Python'у где-то 15лет . Хотя, вроде выглядит молодо

15лет современому python'у и 29 в целом пютону

Про Аду конечно не сказано главное. А именно, наличие её формально верифицированного подмножества SPARC , на котором, в свою очередь, можно писать формально верифицированные программы (верифицировать конечно придётся в ручную, но вам хотя бы не придётся доказывать корректность языковых конструкций и стандартной либы). Именно поэтому аду используют в авиации, космосе и военке. Баги в прошивке взрывателя атомной бомбы как бы не очень хорошая идея...

Всё-таки SPARK (SPade Ada Reduced Kernel), а не SPARC. Да и с верификацией сейчас стало проще — современные компиляторы Ады могут в качестве прувера использовать Coq.

сорри, очепятался

прошивки во взрывателе? не думаю. да конечно система управления МБР -- это комп и там есть прошивка, но вот взрыватель?

В американских зарядах (о них больше известно из открытых источников) именно так. Это часть системы PAL - Permissive Action Link.

Прикол в том, что для правильной имплозии нужна настолько синхронная подача импульса на точки инициации, что важна даже длина проводов от батареи конденсаторов. На этом и построили защиту - ставят провода рандомной длины, соответственно бомбу не подорвешь, не зная правильных значений поправок по времени. Поправки записаны в БК боеголовки и зашифрованы тем самым кодом из голливудских фильмов.

А код - это все нули?

https://habr.com/ru/articles/204948/

Да, был такой исторический прикол. Однако код это еще не самый сложный элемент защиты. Самый сложный - PAL проверяет, что боеголовка действительно совершила путешествие на ракете - перегрузка в одну сторону, невесомость, перегрузка в другую, и разрешает детонирование только на спуске. То есть, украсть боеголовку, заложить и бахнуть не выйдет даже с правильным кодом.

перегрузка в одну сторону, невесомость, перегрузка в другую

Записывает в блокнотик: "купить центрифугу".

Неа - перпендикулярно перегрузке будет вращение, которого быть не должно. Там же аксель+гироскоп.

Я в курсе — невесомость в центрифуге получить вообще невозможно, это шутка юмора была.

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

Но можно запустить на ракете, причем не обязвтельно баллистической (еще есть крылатые). А раквтными технологиями в наше печальное время не только государства обладают.

Можно даже просто пальнуть из пушки (есть и такие ядреные боеприпасы).

Иетеречно, остались ли вообще в природе свободнопвдаюшие ядреные бомбы? Эти вообще просто роняют, вроде даже с парашютом.

Крылатая и пушка точно не воспроизведут то, что хочет PAL. Баллистическая... ну как минимум это должна быть тоже МБР, а не что-то типа Фау-2. Свободнопадающих давно нет, потому что никто не даст бомбардировщику долететь куда ему надо.

Так ядреные боеприпасы - это не только МБР. Это еще крылатые ракеты и снаряды для орудий. Не думаю, что там стоит такая же хитрая ерунда, которая отслеживает уникальные перегрузки, не достижимые простыми средствами.

Так что стырить могут боеголовку не от МБР, а от крылатой ракеты (можно даже вместе с ракетой и всем остальным) или простой ядреный снаряд от пушки.

Так что надеяться оствется не на какой-то хитрый механизм, а только на приличную охрвну всего этого добра.

стырить могут боеголовку

Украсть, теоретически, возможно, а вот применить очень сложно. Еще в в 70-е годы, как в США, так и в СССР, ядерные боеголовки оснащались системами защиты, приводящими боеголовку в неработоспособное состояние, повреждая критические элементы конструкции при неправильном обращении с ней или при попытке вскрытия.

Хотя это не может предотвратить использование обогащенного урана из боеголовки для изготовления "грязной" бомбы. Но тут тоже требуется высокая квалификация персонала, чтобы остаться живым в процессе извлечения урана и изготовления такой грязной бомбы. Болгаркой боеголовку не разрежешь, так как уран самовоспламеняется на воздухе.

Уран для грязной бомбы бесполезен, как и плутоний. Его в руках можно держать. Радиоактивное заражение создают продукты их деления. И на воздухе воспламеняется он только в виде пыли, в виде куска - обыкновкнная железяка.

Давайте свернем тему. Я знаю даже не один способ изготовления грязной бомбы из урана или плутония, но описывать их на публичном ресурсе меня совершенно не тянет.

Свободнопадающих давно нет, потому что никто не даст бомбардировщику долететь куда ему надо.

На вооружении у США до сих пор есть не только B83, но даже B61 (кроме ранних модификаций). Видимо, рассматриваются сценарии, когда её можно применить.

Удивлён! Интересно было бы услышать комментарий военного, как она могла бы в наши дни пригодиться. Отдать союзнику в случае прекращения действия КНЯО, как слабосекретную вещь, что ли?

Ну тут не исключен вариант Плюшкина )))

Все же только B61 произвели свыше трех тысяч штук.

В конгрессе вопрос об утилизации этих бомб уже не раз поднимался. Последний раз, если мне не изменяет память, в 2022 году. И, как обычно, вопрос упирался в финансирование их утилизации.

Странно. Плутоний так-то недешев, неужели переиспользование их ядер в современных боеголовках не окупит? Или на производство мокс-топлива продать.

Судя по https://ru.wikipedia.org/wiki/Соглашение_об_утилизации_плутония , в США с этим очень плохо:

"В США строительством завода MFFF (англ. Mixed oxide Fuel Fabrication Facility) с 2007 года на площадке Саванна-Ривер занималась Duke Cogema Stone (ныне — Shaw-AREVA MOX Services[23]), проект оценивался в 4,8 млрд долл, однако с 2013 года наблюдаются проблемы с финансированием и строительство было остановлено на уровне около 70 % готовности[24][25][26][27]. 8 февраля 2019 года Комиссия по ядерному регулированию (NRC) США аннулировала строительную лицензию для MOX-завода в Саванна-Ривер, на строительство было потрачено 8 млрд. долларов, для достройки просили выделить из бюджета ещё 17,3 млрд., но оказалось проще закрыть завод."

Когда учился в институте (82-88гг), военка была еще обязательна (штамповали офицеров запаса). У нашего факультет была ВУС 420300/6 - "Инженер по ремонту ЭСО и автоматики танков или помощник начальника бронетанковой службы Т и МСП по электроспецоборудованию". Сборы мы проходили в части, которая являлась "базой хранения БТТ". Так вот, там в огромном количестве стояли "новенькие" ИСУ-152 - их (и выстрелов для них) под конец войны наделали огромное количество, значительная часть даже до фронта доехать не успела.

Позже их доукомплектовали системами пожаротушения (они в БТТ уже после войны - по легенде ее в изначальном варианте разработала женщина у которой муж в танке сгорел в войну) и современными (на тот момент, естественно) радиостанциями.

Хранилось все это "на случай если что" - понятно что в современных условиях оно долго не проживет, но за счет огромного количества хоть какую-то пользу принесет - несколько раз выстрелить таки успеет. Ну а дальше уже что-то более современное подтянется.

Такая схема давно устарела, синхронизм обжатия достигается конструктивно, а до этого вообще применялась детонирующая разводка по поверхности, сейчас достаточно двух детонаторов. Вот в какое время начнет работать НИ, когда выдаст импульс - от этого напрямую зависит энерговыделение. Может и пшикнуть, а может и ого.

Хм. Насколько я читал, dial-a-yield реализуется уже на стадии синтеза- дозированием нужного количества дейтерида лития внутрь заряда деления, а хранится он в сторонке от него.

Апд: погуглил - и правда, и так и так делают.

Вы будете смеяться, но атомную бомбу гораздо сложнее взорвать (в смысле именно как ядерную, а не как грязную), чем не взорвать.

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

Стариков конечно нужно почитать и вспоминать, но от того жизнь не перестает идти вперед.
Я к тому, что - а статься про самые новенькие и многообещающие языки будет?

Rust, Julia, Crystal - о них много статей есть, толку то

будто о COBOL, FORTRAN, LISP мало)

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

а от чего ещё торчать? если не от кобола

а вы его видели?

"Комплексные числа как встроенный тип данных — это крайне важно для расчётов в области радиофизики."

Как заржал ночью! ))

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

А что вас в этом предложении рассмешило?

Если в расчетах используются комплексные числа, удобно, если они реализованы непосредственно в языке как встроенный тип данных (не надо делать самому или искать готовую реализацию). Удобство для программиста - это крайне важно, он делает меньше ошибок. В радиофизике комплексные числа очень даже используются.

Единственое непонятно, почему из всех областей, где комплексные числа пользуют, именно радиофизику автор вспомнил.

Наверное, потому, что в свое время Институт Радио активно использовал эту возможность PL/I. А когда появились первые IBM-PC/XT, они даже купили транслятор PL/I-86, чтобы быстро уйти с EC-ЭВМ, не переделывая программ. Но как раз этой возможности там и не оказалось (

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

Тут ещё проблема в том, что реализация поверх языка неизбежно будет менее эффективна.

а есть обоснования? За счёт чего так.

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

Плюс оптимизация арифметических выражений

соглашений о связях.


не понял до конца что вы имеете ввиду. Если вы про ABI, то встроенные операции тоже должны его выполнять. Если про вызовы функций из shared либы, то не стоит забывать про static.

Писать на ассемблере и не очень нужно чаще всего. Ведь придется переписывать код под разные архитектуры. Но есть низкоуровневые приемы в самом языке, которые помогают подтолкнуть компилятор к нужным оптимизациям. Я говорю за C++/C только. Поэтому, я думаю, оптимизация тут роли не играет.

Даже в языке C/C++, где формально функции стандартной библиотеки не являются частью языка, оптимизирующий компилятор, тем не менее, осведомлён о семантике элементарных функций и компилирует прямо в арифметические машинные инструкции, а не в вызовы подпрограмм в соответствии с соглашениями о связях. Например, функция sqrt будет скомпилирована clang непосредственно в одну машинную инструкцию vsqrtsd. К сожалению, очень эффективные в системе команд SSE функции max и min в языке C не определены, а в языке С++ определены через уродливый макрос, поэтому компилируются в менее эффективные ветвления, а не более в эффективные vpmaxsd и vpminsd, но, во-первых, в предназначенном для эффективных расчётов Фортране такой проблемы нет, а во-вторых, всё равно даже встроенные в код ветвления эффективнее, чем вызов подпрограммы с теми же ветвлениями.

Что касается ассемблера, то многие библиотеки для численных расчётов включают ассемблерные функции. Все библиотеки Intel, например, реализованы в вычислительной части в машинном коде. Но и часть библиотек третьих авторов тоже.

в языке С++ определены через уродливый макрос, поэтому компилируются в менее эффективные ветвления, а не более в эффективные vpmaxsd и vpminsd

Всё-таки через функции (std::max), компилируются в GCC и Clang как раз в AVX'овые vpmaxsd: https://godbolt.org/z/PecT7zvd4

В <algorithm> было написано (по крайней мере, в 11-м clang) буквально следующее:

template <class _Tp, class _Compare>
_LIBCPP_NODISCARD_EXT inline
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const _Tp&
max(const _Tp& __a, const _Tp& __b, _Compare __comp)
{
    return __comp(__a, __b) ? __b : __a;
}

Хорошо, если это исправили.

Замысел-то понятен – обеспечить применимость ко всем упорядоченным классам. Но такой ценой это нафиг не упало.

См. ниже. Любая переменная суть набор байт в ячейке памяти. Если ваш язык поддерживает некий тип переменных - вы просто копируете эти байты в ячейку связанную с переменной нужного типа и дальше с ней работаете.

Если же этот тип реализован поверх языка, скажем, в виде какого-то класса, то прежде чем работать с объектом этого класса, вам потребуется (в рантайме!) создать его, вызвав конструктор (даже сам вызов конструктора уже не бесплатен т.к. фактически это функция, создающая и потом сворачивающая новый уровень, а может и не один, если там несколько уровней абстракции наворочено, стека) с передачей туда этого самого набора байт.

Ну вот конкретный пример. Работаем на платформе IBM i, основной язык RPG. В целом все сводится к работе с БД и обработке лежащей там информации в соответствии с логикой бизнес-процессов.

RPG для нас удобен прежде всего тем, что в нем нативно поддерживаются все типы данных, что есть в БД - decimal, numeric, date, time, timestamp... Т.е. можно определить структуру, соответствующую формату записи в БД (для этого даже не нужно описывать все поля - в языке есть специальный способ объявления

dcl-ds t_dsYAR  likerec(YAR12LF.YARPFR: *all) template;

что означает "объявление шаблона (типа) структуры данных, соответствующей формату записи YARPFR в файле YAR12LF".

Имена и типы полей структуры будут такими же как имена и типы полей в записи.

Все. Дальше достаточно в эту структуру прочитать нужную запись и дальше уже можно напрямую работать с полями - производить над ними любые поддерживаемые для соответствующих типов операции.

Для языков, где все это реализовано "поверх" (Java, С/С++ и т.п.) Пришлось бы читать запись в байтовый буфер, а потом из него создавать объекты нужных типов. Т.е. вызывать какие-то конструкторы, которые что-то там будут делать и т.п. В рантайме.

А когда "нормальной" считается выборка в несколько [десятков] миллионов записей, производить какие-то операции над каждой записью после ее чтения и до, собственно, работы с ее содержимым - это уже вполне ощутимые накладные расходы.

Не говоря уже о необходимости тащить в проект лишние зависимости.

Да, подобные языки не являются в полном смысле "языками общего назначения", он скорее специализированные для решения определенного класса задач. Но для этих задач они и удобнее (в разработке) и быстрее (в работе) "общих" языков.

Это же самое преобразование в РАН тайм на том же "С" разве не решается банальным union?

Совсем недавно, летом переводил таким способом сообщения маслины протокола в структуру данных для дроноведов..

Не совсем понятно у каких юнионах идет речь?

Есть у вас в БД лежит набор байт, представляющий из себя какое-то значение в формате numeric, decimal, date, time, timestamp - с чем вы будете го объединять чтобы потом можно было сделать, например

a += 5;

и записать обратно в БД в том же формате?

Способ хранения в памяти, скажем, для decimal(15, 5) и какого-нибудь double радикально разные. И это даже не int или еще что-то что поддерживается сишным компилятором. Максимум что так можно обойти - varchar ибо varchar(50) аналогичен (по хранению в памяти)

typedef struct tVarChar {
  unsigned short len;
  char data[50];
};

Но это пожалуй единственная ситуация, где можно выкрутиться

typedef union uVarChar {
  char data[52];
  struct tVarChar varchar;
};

С остальными же типами такое уже не пройдет.

так все ведь просто только если в бд данные представлены в том же виде, в котором в языке. Тогда просто копируются байты.
Если же они в другом формате, что скорее всего - ведь количество бд хоть отбавляй, то также приходится в рантайме конструировать тип. Тут лишь одно преимущество - может быть код, который написали для создания встроенных типов, более быстрый качественныый. Ито это не аргумент.

Если же говорить том, когда формат данных совпадает, то и в тех же плюсах нет никакой проблемы использовать эти байтики сразу как тип и без какого-либо рантайм оверхеда на конструирвоание/копирование.

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

Насчет удобства трудно сказать. Я бы не сказал что приведенный вами код читаем и прост. Хотя скорее всего на это сказывается мой опыт с сиподобным синтаксисом.

Честно говоря, мне тяжело представить, что сейчас у языков из статьи есть какое-либо преимущество перед современными. Был бы рад почитать статью, где показывают как один и тот же код на RPG/[any other] быстрее/читаеме/удобнее чем какой-нибудь C/C++/Java/Python

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

Я писал ужа - RPG интегрирован в конкретную платформу (IBM i) и тьесно связан с интегрированной в нее же БД ( DB2). Именно поэтому практически неизвестен за пределами этой экосистемы.

И да. Представление этих типов в языке точно такое же как в БД. Т.е. никаких накладных расходов.

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

Речь не о том что дороже. Речь о том, нужно ли что-то еще делать между запросом и работой с данными.

Насчет удобства трудно сказать. Я бы не сказал что приведенный вами код читаем и прост. Хотя скорее всего на это сказывается мой опыт с сиподобным синтаксисом.

Не поверите, но я 25+ писал на С/С++. И сейчас немного пишу, когда нужно реализовать что-то низкоуровневое (да, компиляторы С/С++ тут тоже есть).

Более того, здесь есть ILE Здесь не ассемблера - есть "машинные инструкции" (MI). И компиляторы любого поддерживаемого языка генерируют однотипный промежуточный код в MI. Который потом уже транслируется в исполняемый на этапе сборки.

Т.о. (если на пальцах) модуль (системный объект типа *MODULE - аналог объектного файла), скомпилированный компилятором RPG на 100% совместим с модулем, скомпилированным компилятором C/C++ И могут быть слинкованы (bind) в одну программу (программный объект - *PGM).

Так вот, о чем я... Более 6-ти лет RPG основной язык. И для меня он ничуть не хуже читаем, нежели С/С++. Более того, он проще. Намного проще.

Тот код, который вам показался "плохочитаемым" на С выльется в очень длинную структуру - есть таблицы, где запись содержит насколько десятков полей. На С вы будет ее руками колотить. Тут одна строка со ссылкой на формат.

Концепция структур в RPG намного гибче оной в С. Здесь это байтовый буфер (и вы можете явно задать его длину) с размеченными внутри полями. При необходимости вы можете явно задать для каждого поля его позицию в буфере.

Пример. У вас есть буфер в 512 байт, который что-то там содержит. Но вас тут интересуют только строка в 10 байт в 50-й позиции и строка в 20 байт в 125-й

dcl-ds dsBuffer len(512) qualified;
  str1 char(10) pos(50);
  str2 char(20) pos(125);
end-ds;

Все.

Более того, поля могут перекрываться (привет С-шным union - тут они просто не нужны).

Возможны неименованные поля (привет всяким tmp, dummy, reserved и иже с ними)

При объявлении шаблона структуры (аналог typedef stuct) можно сразу задавать значения полей, которыми он будут проинициализированы. Тогда все структуры, созданные по этому шаблону сразу (на этапе компиляции) будут проинициализированы указанными значениями.

// Описываем шаблон структуры
dcl-ds t_dsISODate qualified template; 
  year   char(4)  inz('0001');
  *n     char(1)  inz('-');            // неименованное поле - разделитель
  month  char(2)  inz('01');
  *n     char(1)  inz('-');
  day    char(2)  inz('01');
  dteStr char(10) pos(1);              // поле, перекрывающее все предыдущие
end-ds;

// Создаем переменную по шаблону и сразу инициализируем как приписано в шаблоне
// Это все на этапе компиляции - dsISODate.dteStr сразу содержит '0001-01-01'
dcl-ds dsISODate likeds(t_dsISODate) inz(*likeds);

// а если так
dsISODate.year  = '2024';
dsISODate.month = '02';
dsISODate.day   = '19';

// то в dsISODate.dteStr получим '2024-02-19'

Есть и более хитрые штуки. Например, у нас есть т.н. "тринадцатизначный счет" - строка 12 символов, состоящая из 3-хчастей - AB, AN и AS - 4, 6 и 3 символа соответственно (например, 0124UA3IZX002. И можно определить массив счетов вот так:

// Сразу опделеняем переменную, не шаблон
dcl-ds dsAcc13 qualified;
  Acc13   char(13)  dim(100); // ну пусть будет 100 для примера
    AB    char(4)   overlay(Acc13);
    AN    char(6)   overlay(Acc13: *next);
    AS    char(3)   overlay(Acc13: *next);
end-ds;

При таком описании можно обращаться как ко всему счету целиком - dsAcc13.Acc13(i), так и к любой его составляющей по отдельности (точно также, как к элементу массива) - dsAcc13.AB(i), dsAcc13.AN(i), dsAcc13.AS(i)

Еже сахарок - вместо всех этих сишных

#define    SHRT_MIN       (-32768)
#define    SHRT_MAX       32767
#define    USHRT_MAX      65535U

#define    INT_MIN        (-2147483647-1)
#define    INT_MAX        2147483647
#define    UINT_MAX       4294967295U

#define    LONG_MIN       (-2147483647L-1L)
#define    LONG_MAX       2147483647L
#define    ULONG_MAX      4294967295UL

#define    LONGLONG_MIN   (-9223372036854775807LL-1LL)
#define    LONGLONG_MAX   9223372036854775807LL
#define    ULONGLONG_MAX  18446744073709551615ULL

#define    LLONG_MIN      (-9223372036854775807LL-1LL)
#define    LLONG_MAX      9223372036854775807LL
#define    ULLONG_MAX     18446744073709551615ULL

Есть просто *loval и *hival которые компилятор понимает как "минимально/максимально возможное значение для данной переменной в соответствии с ее типом.

Там еще много чего. Ну синтаксис - дело привычки. Главное - простота и гибкость работы со сложными структурами данных и нативная поддержка все имеющихся в БД типов. Ну и возможность работы с БД как напрямую (позиционирование по индексу, чтение-запись-удаление), так и встроенным SQL. Например (что попроще, на самом деле там все намного сложнее можно наворотить)

// структура куда будем получать результа запроса
dcl-ds dsHDARes qualified;
  DAT           zoned(7:0) inz;
  USID          char(4);
  UNAM          char(35);
  BRNM          char(4);
  BRN           char(35);
  CRD           timestamp inz(*loval);
  MBN           char(2);
  MBND          char(35);
  SQN           zoned(3:0) inz;
End-DS;

// собственно запрос
exec sql select HDA1DAT,
                HDAUSID,
                HDAUNAM,
                HDABRNM,
                HDABRN,
                HDACRD,
                HDAMBN,
                cast(coalesce(substr(GPVDSC, 1, 35), '') as char(35)),
                HDA1SQN
           into :dsHDARes
           from HDA1PF
           join HDAPF 
             on (HDACUS, HDACLC, HDATYP, HDADAT, HDASQN) =
                (HDA1CUS, HDA1CLC, HDA1TYP, HDA1DAT, HDA1SQN)
      left join GPVPF on (GPVITM, GPVVLE) = ('DAMBN', HDAMBN)
          where (HDA1CUS, HDA1CLC, HDA1TYP) = (:CUS, :CLC, :Typ);

// Тут dsHDARes уже заполнена соотв. значениями с которыми можно работать напрямую, без каких-либо дополнительных преобразований

Это т.н. "статический SQL". Может быть еще и динамический (когда строка запроса формируется в рантайме) - там побольше телодвижений, но суть та же.

Повторюсь - язык под конкретную платформу и для конкретных целей. Но на этой платформе и для этих целей он крайне удобен, быстр и эффективен. Как в разработке, так и в выполнении.

Честно говоря, мне тяжело представить, что сейчас у языков из статьи есть какое-либо преимущество перед современными. Был бы рад почитать статью, где показывают как один и тот же код на RPG/[any other] быстрее/читаеме/удобнее чем какой-нибудь C/C++/Java/Python

А на слово поверите? У нас каждая поставка проходит нагрузочное тестирование - есть специальный инструмент - Performance EXplorer (PEX). Так вот он все показывает - как использование ресурсов, так и быстродействие. Проверяли - на сложной логике плюсовый код будет более запутан, громоздок и при этом проиграет по эффективности RPGшному.

Любой язык, специализированный поди конкретную платформу и задачи всегда эффективнее яву р щено назначения. Банальность, однако.

Перечитал. Т9 отжег сильно конечно.. ;) Должно было быть так:

Любой язык, специализированный под конкретноую платформу и задачи, всегда эффективнее ЯВУ общего назначения.

Да. Именно это и только это я и пытаюсь сказать.

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

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

Никому в голову не придет писать что-то системное на фортране. Да даже то, что связано с массовой обработкой текстовых данных.

Так и у нас - если нужно что-то низкоуровневое, какие-то API для удобной работы с системными объектами - тут С/С++. Но для работы с БД и бизнес-логики - тут RPG со всех сторон эффективнее.

Пример. У вас есть буфер в 512 байт, который что-то там содержит. Но вас тут интересуют только строка в 10 байт в 50-й позиции и строка в 20 байт в 125-й

Прошу прощения, но у Вас тут или речь о бинарных данных, или байты с символами перепутались. Все же сейчас уже почти все перешли на UTF-8 и один символ может занимать от 1 до 4 байт.

Использование CHAR вместо VARCHAR выглядит очень странно. На практике, разве что CHAR(1) иногда использую. Во всех остальных случаях - VARCHAR. И разработку существенно упрощает и память экономит.

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

Ну и, уже в виде лирики, с такими именами таблиц и полей я бы PR точно завернул. Все же имена должны быть элементом самодокументирования кода.

А вообще выглядит страшно. Я не подвергаю сомнению эффективность, но трудоемкость написания кода на Java или C# уж точно будет ниже.

Тут dsHDARes уже заполнена соотв. значениями

Этого тоже не понял. dsHDARes - это что ли поток, а не структура? Или массив в который всегда сразу загружаются все записи из рекордсета? А если просто мэппинг, то тогда зачем вообще описывать структуру dsHDARes, если она может быть автоматически создана по результату запроса? Ведь типы всех полей в БД уже известны. Ну это если парадигма Database-First, а не Code-First. В последнем случае и запрос выписывать не надо и проблема мэппинга вообще не стоит.

Прошу прощения, но у Вас тут или речь о бинарных данных, или байты с символами перепутались. Все же сейчас уже почти все перешли на UTF-8 и один символ может занимать от 1 до 4 байт.

На этой платформе работаем с однобайтовой кодировкой EBCDIC 1025

UTF-8 поддерживается, но надо ставить дополнительный модификатор ccsid(1208)

Использование CHAR вместо VARCHAR выглядит очень странно. На практике, разве что CHAR(1) иногда использую. Во всех остальных случаях - VARCHAR. И разработку существенно упрощает и память экономит.

Нет. VARCHAR не экономит память. Это не динамическая строка. Это строка аналогичная структуре

struct {
  unsigned short len;
  char data[50];
};

суть VARCHAR(50) (длина может кодироваться 4-байтовым unsigned, тогда VARCHAR(50: 4).

Тут все удобство в том, что конец строки (длина) указывается явно, а не по завершающему \0 как в С или не забит пробелами (как в RPG). Т.е. реальная длина строки

a = %len(vchStr);        // для varchar
a = %len(%trimr(chStr)); // для char

или

vchStr1 += vchStr2                // для varchar
chStr2 = %trimr(chStr2) + chStr1; // для char

В БД немного иная ситуация. Там можно сэкономить память для длинных строк в том случае, когда у вас в подавляющем большинства случаев не используются строки максимальной длины - можно задать allocated length меньшей длины. Но для таблиц с высокой интенсивностью записи это приводит к просадке производительности как правило. Особенно при плохом выборе allocated length.

Так что в БД varchar практически не используем.

Ну и, уже в виде лирики, с такими именами таблиц и полей я бы PR точно завернул. Все же имена должны быть элементом самодокументирования кода.

Имена полей в БД ограничены 10-ю символами. Так что "самодокументированность" реализуется несколько иначе - через описания и заголовки полей

  -- Задаём название таблицы
  LABEL ON TABLE NMCPF IS 'Связь наименований/ФИО с клиентами';

  -- Задаём описание колонок каждого поля (A maximum of three lines of 20 characters each is allowed)
  LABEL ON COLUMN NMCPF (
    NMCCUS is 'Мнемоника           клиента',
    NMCCLC is 'Местоположение      клиента',
    NMCNTP is 'Тип                 наименования',
    NMCTP  is 'Класс               клиента',
    NMCID  is 'ID                  наименования',
    NMCDT  is 'Дата последнего     изменения'
  );

  -- Задаём текстовое описание каждого поля (only the first 50 characters are used)
  LABEL ON COLUMN NMCPF (
    NMCCUS text is 'Мнемоника клиента',
    NMCCLC text is 'Местоположение клиента',
    NMCNTP text is 'Тип наименования',
    NMCTP  text is 'Класс клиента',
    NMCID  text is 'ID наименования',
    NMCDT  text is 'Дата последнего изменения'
  );

на DML или

     A            CPFCHK        10A         TEXT('Название -
     A                                      проверки')
     A                                      COLHDG('Проверка')
     A            CPFDSC       100A         TEXT('Описание -
     A                                      проверки')
     A                                      COLHDG('Описание')
     A            CPFPGM        10A         TEXT('Функция -
     A                                      проверки')
     A                                      COLHDG('Функция')
     A            CPFULM         4A         TEXT('Пользователь -
     A                                      последнего изменения')
     A                                      COLHDG('Пользователь')
     A            CPFTLM          Z         TEXT('Время -
     A                                      последнего изменения')
     A                                      COLHDG('Дата и время')

на DDS.

трудоемкость написания кода на Java или C# уж точно будет ниже

Нет. У вас будут сложности с SQL, у вас будут сложности с трансляцией типов, вам придется тянуть огромную кучу зависимостей (и следить за из версиями).

dsHDARes - это что ли поток, а не структура? Или массив в который всегда сразу загружаются все записи из рекордсета? А если просто мэппинг, то тогда зачем вообще описывать структуру dsHDARes, если она может быть автоматически создана по результату запроса?

Это не мэпппинг. Тут нет мэппинга. Это буфер. Хост-переменная куда загружается результат запроса. В данном случае результат всегда одна строка. Если результат многострочная выборка - там иначе.

      dcl-ds t_dsSQLData qualified template;
        CUS  char(6)     inz;
        CLC  char(3)     inz;
        SER  char(10)    inz;
        NUM  char(35)    inz;
        OPN  zoned(7: 0) inz;
        EDT  zoned(7: 0) inz;
        OSN  char(1)     inz;
      end-ds;

шаблон структуры - результат выборки

        exec sql declare curRDKMSClients1 cursor for
                 select RDKCUS,
                        RDKCLC,
                        RDKSER,
                        RDKNUM,
                        RDKOPN,
                        RDKEDT,
                        RDKOSN
                   from RDKPF RDK
                   join GFPF 
                     on (GFCUS, GFCLC, GFCTP) = 
                        (RDK.RDKCUS, RDK.RDKCLC, :cltType)
                    and GFDEL <> 'Y'
                   join CAFPF
                     on (CAFCUS, CAFCLC, CAFATR1) =
                        (RDK.RDKCUS, RDK.RDKCLC, 'Y')
                   join UIDPF
                     on (UIDCUS, UIDCLC, UIDSTS, UIDTPI) =
                        (RDK.RDKCUS, RDK.RDKCLC, 'A', '')
                  where (RDKUCD, RDKSDL) = ('001', 'Y')
                    and RDKEDT >= :$Date0
                    and RDKEDT <= :$DateK;

объявление курсора (статический SQL).

dcl-ds dsSQLData  likeds(t_dsSQLData) dim(sqlRows);

Объявление массива строк куда читаем

exec sql open curRDKMSClients1;

Открытие курсора

Дальше в цикле чтение

dou lastBlock;
  exec sql fetch curRDKMSClients1 for :sqlRows rows into :dsSQLData;

  lastBlock = sqlGetRows(rowsRead);

  for row = 1 to rowsRead;
    getClientPhone(dsSQLData(row).CUS: dsSQLData(row).CLC: Phone);
    getClientInfo(dsSQLData(row).CUS: dsSQLData(row).CLC: 
                  Name: Age: Packet: Segment: Branch);
    CYMD2EUR(dsSQLData(row).EDT: EndDte);

    sndMessage(msgType: msgSts: cntMsg: dsSQLData(row).CUS: 
               dsSQLData(row).CLC: Name: dsSQLData(row).NUM: 
               dsSQLData(row).SER: dsSQLData(row).OPN: 
               EndDte: Age: Packet: Segment: Branch: Phone);
  endfor;
enddo;

И пока что-то есть - обработка очередной прочитанной порции данных из массива dsSQLData.

Количество реально прочитанных строк и (заодно) есть ли еще что читать

      //=======================================================================
      // Процедура получения количества прочитанных строк в SQL запросе
      //=======================================================================
      dcl-proc sqlGetRows;
        dcl-pi *n ind;
          sqlRowsRead  int(10);
        end-pi;

        dcl-s  sqlRowCount  packed(31 : 0) inz(*zero);
        dcl-s  sqlDB2LstRow int(10)        inz(*zero);

        exec sql GET DIAGNOSTICS
                :sqlRowCount  = ROW_COUNT,
                :sqlDB2LstRow = DB2_LAST_ROW;

        sqlRowsRead = sqlRowCount;

        return (sqlDB2LstRow = 100);

      end-proc;

Это Embedded SQL - он результат всегда помещает в хост-переменную. В буфер с которым потом уже работаем.

Аналогичным образом работает прямой доступ к БД, без SQL. Он эффективнее когда, например, надо из одной таблицы прочитать одну запись по известному значению ключа

        dcl-f RDKM01LF    disk(*ext)
                          usage(*input)
                          usropn
                          keyed
                          qualified
                          static;

Определили файл ("логический файл" - индекс фактически).

dcl-ds dsRDKM     likerec(RDKM01LF.RDKMPFR: *all);

Определили структуру со ссылкой на структуру записи в файле. На другом языке вам пришлось бы все поля (а их в некоторых таблицах может быть пара-тройка десятков) описывать отдельно. Тут - одной строкой.

chain (dsSQLData(row).CUS: dsSQLData(row).CLC: '001': 
       dsSQLData(row).SER: dsSQLData(row).NUM: 
       dsSQLData(row).OPN: '1') RDKM01LF.RDKMPFR dsRDKM;

Прочитали в нее запись из таблицы по ключу.

Также эффективнее проверять наличие записи с заданным значением ключа в таблице

setll (dsSQLData(row).CUS: dsSQLData(row).CLC: '001': 
       dsSQLData(row).SER: dsSQLData(row).NUM: 
       dsSQLData(row).OPN: '2') RDKM01LF;

if %equal(RDKM01LF);
  // что-то делаем если запись есть
endif;

Тут нас не интересует содержимое записи. Только есть такая или нет. Он не полезет в саму таблицу ("физический файл"), только проверит наличие записи в индексе ("логическом файле")

На этой платформе работаем с однобайтовой кодировкой EBCDIC 1025

Мы даже на MS SQL уже получили море проблем из-за его UTF-16, в который тупо не влазят все возможные символы UTF-8, регулярно прилетающие из внешних источников. Как сейчас жить с однобайтовой кодировкой, когда даже официальные наименования встречаются с трехбайтовыми UTF-8 символами - вообще не представляю.

Нет. VARCHAR не экономит память. Это не динамическая строка. Это строка аналогичная структуре

Если это так на DB2, то я в шоке. Например, в PostgreSQL и длина, и значение являются динамическими массивами байт. Размер длины ограничивается байтом с установленным в единицу старшим битом. Размер данных ограничивается при сборке по умолчанию 1ГБ, но при желании перекомпиляцией может быть увеличен вплоть до 32 ТБ.

То есть, такой подход позволяет экономить память уже буквально на строках короче двух байт, по сравнению с установленным constraint. Ведь VARCHAR(n) отличается от VARCHAR только constraint n, ограничивающем допустимую длину. Само внутреннее представление ничем не различается.

Имена полей в БД ограничены 10-ю символами.

Это такое издевательство от IBM? В XXI веке имена короче 30 символов (до 120 байт в UTF-8) - выглядят именно так.

Так что "самодокументированность" реализуется несколько иначе - через описания и заголовки полей

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

У вас будут сложности с SQL, у вас будут сложности с трансляцией типов, вам придется тянуть огромную кучу зависимостей (и следить за из версиями).

Вообще не понял о чем Вы. Давайте сначала хотя бы уточните, Вы о парадигме Database-First, когда модель БД в языке автоматически генерируется на основании метаданных БД или о парадигме Code-First, когда метаданные БД автоматически генерируются на основании модели в коде? Или мы опять возвращаемся в прошлый век, когда структуры данных в БД и в языке программирования описывались по отдельности?

Это буфер.

Буфер на одну запись? Не слишком ли жирный расход памяти? А если в ней массив композитного типа, который вправе занимать до 32 ТБ, то вся запись что ли всегда считывается полностью, а не частями потоком?

Например, в PostgreSQL буфера всегда фиксированного размера, что намного удобней, существенно экономит память и повышает производительность не только при обработке многомегабайтных строк, но и при обработке больших массивов или XML/JSON.

Так же совершенно непонятно, что делать, если до выполнения запроса его структура просто не известна, например, из-за композитных типов возвращаемых функциями. То есть какое-то поле может как присутствовать, так и отсутствовать.

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

Доступ к кортежу и его полям через методы выглядит намного эффективней и удобней, чем предварительное прибивание гвоздями структуры данных в памяти к кортежу, порождающее кучу ограничений. В современный фреймворках вам не надо даже думать, что в БД CHAR(4) стал уже CHAR(10) или DECIMAL(12,2) превратился в DECIMAL(18,4), так как типы полей обрабатываются автоматически. А здесь будете получать исключения, если RPG в состоянии понять, что вместо последовательных полей CHAR(4) и CHAR(10) он получил CHAR(6) и CHAR(8). Если не в состоянии, то ситуация вообще становится плачевной.

В данном случае результат всегда одна строка.

Даже в этом случае пример не показателен, так как не содержит полей неизвестной до выполнения запроса длины, которая вполне может быть как сотни мегабайт, так и единицы байт.

Открытие курсора

Но курсор ведь намного менее эффективней, чем последовательная выборка результата, так как хуже буферизируется и требует больше накладных расходов от СУБД. Зачем он тут?

Кстати, асинхронности я тут тоже не заметил. Или RPG не позволяет через async/await обрабатывать данные пока СУБД выполняет очередной запрос? Все же синхронная работа с СУБД очень не эффективна и редко применяется.

Также эффективнее проверять наличие записи с заданным значением ключа в таблице

В Java/C# вообще не приходится задумываться о БД в этом случае. Сразу if или лямбда. SQL начинается только на сложных запросах, где тот же linq катастрофически тупит при построении SQL запроса. Хотя эта проблема решаема функциями и представлениями в БД.

Вообще у меня сложилось впечатление, что на RPG, например, отпарсить сообщения protobuf из логов в БД - легче повеситься.

Похоже вы мыслите категориями, когда приложение пишется на одном стеке технологий, база живёт каком-то в своем мире, а единственный способ общения между ними - некий протокол через узкую дырочку.

В случае мейнфреймов от IBM это не так. Здесь база и приложение являются частью одной системы.

Близкий аналог - хранимые процедуры на PL/SQL, - где и логика, и SQL представляют собой один сценарий, который исполняется в общей среде.

Просто в случае IBM такой код исполняет не СУБД, а, грубо говоря, сама операционная система. Представьте себе операционную систему, которая помимо shell скриптов и бинарных программ, может так же нативно исполнять PL/SQL. При этом, передача данных между всеми ними сводится к виртуальному отображению значений в нужные куски памяти - безо всяких protobuf и прочей промежуточной ерунды.

Да, именно так.

Это кажется непривычным, но БД - это часть операционки. Как и компиляторы языков.

Поэтому все это вместе работает очень эффективно. Я могу выполнять SQL запросы из RPG программ, а могу писать хранимые SQL процедуры на RPG.

А могу мешать внутри одной программы языки - часть функций писать на С/С++, часть на RPG.

В случае мейнфреймов от IBM это не так. Здесь база и приложение являются частью одной системы.

Но при этом, в общем случае, сотни хостов все равно будут обмениваться через друг с другом через какой-то протокол. Даже если база шардирована и иным способом распределена на десяток мастеров, клиентских сервисов все равно тысячи. И уже проблемы k8s на каком именно из хостов очередной сервис или его копию запустить. Какой бы производительный не был мейнфрейм, но даже всего сотня недорогих и типовых 64-ядерных серверов окажутся производительней.

Близкий аналог - хранимые процедуры на PL/SQL, - где и логика, и SQL представляют собой один сценарий, который исполняется в общей среде.

Что уже давно считается антипаттерном, так как хост с СУБД - всегда узкое место и его, рано или поздно, приходится разгружать от таких задач. А мультимастер в том же Oracle тут не панацея. Даже на десятке хостов он уже выглядит печально. Тогда как шардирование позволяет параллелить тысячи хостов с почти линейным ростом производительности, хоть и некоторой ценой усложнения разработки.

При этом я не увидел ответа на вопросы:

  • Как в RPG обрабатываются поля переменной или даже неопределенной на момент начала выполнения запроса длины?

  • Буферизируется вся запись, даже если она занимает терабайты?

  • О какой огромной куче зависимости идет речь, если не дублировать структуры БД руками в коде?

  • Как в RPG реализуется асинхронность?

  • Система в любом случае коммуницирует с внешним миром, а protobuf - один из наиболее производительных форматов для этой цели. Чем он Вам не угодил?

Какой бы производительный не был мейнфрейм, но даже всего сотня недорогих и типовых 64-ядерных серверов окажутся производительней.

Тут еще вопрос надежности. И цены.

У нас сейчас 120 8-поточных ядер Power9.

Для объединения серверов вообще-то есть NUMA, CAPI, PowerAXON. Почитайте вот про новые Power10 Сильно сомневаюсь что вы их чем-то дешевым так просто замените без потери функциональности.

  • Как в RPG обрабатываются поля переменной или даже неопределенной на момент начала выполнения запроса длины?

Можно пример где и зачем это может понадобится?

Просто интересно в каких практических приложениях это можно эффективно использовать.

У нас я таких задач не могу себе представить. У нас есть набор атомарных сущностей - клиент, счет, карта, клиентские данные (которые тоже суть набор - ДУР, ФИО, ДР и т.п.) Их очень много, но нет ни одного бизнес-процесса, который использовал бы их все. Каждый процесс работает со своим набором - где-то счета, где документы (ДУЛ, доверенность и т.п.), где-то еще что-то.

И каждый процесс формирует под себя нужный ему поток данных (выборку - набор необходимых данных + условия отбора) с которым работает.

Запихать все в одну запись? Это нерационально и снижает производительность.

Асинхронная работа тут тоже ни к чему. Бизнес-процесс работает в отдельном задании (параллельно с десятком тысяч других процессов). И пока он не получит поток данных, ему просто нечего делать.

И да, когда речь идет о выборках в десятки миллионов записей, естественно, ни SQL движок, ни прямой доступ все в память разом не тянут - получают частями.

  • Буферизируется вся запись, даже если она занимает терабайты?

Опять же - что может сподвигнуть на создание терабайтных записей? Что буферизируется внутри того же SQL движка я не в курсе. Это все уже (я подозреваю) под SLIC лежит и обычному разработчику недоступно. С SQL из языка работа идет через SQLDA, SQLCA и хост-переменные являющиеся параметрами запроса.

Если для прямого доступа к БД еще можно управлять размером буфера (используется в режиме блочного чтения-записи), то SQL это вещь в себе.

  • О какой огромной куче зависимости идет речь, если не дублировать структуры БД руками в коде?

Библиотеки, реализующие работу с БД, типы данных которые есть в БД, но нет в языке и т.п.

  • Как в RPG реализуется асинхронность?

В языке - никак. На уровне системы - зависит от конкретной задачи.

  • Система в любом случае коммуницирует с внешним миром, а protobuf - один из наиболее производительных форматов для этой цели. Чем он Вам не угодил?

В нашем случае используются очереди (IBM MQ, Kafka) или веб-сервисы. Архитектура системы такова, что мастер-система не отдает и не принимает терабайты данных (и вообще изолирована от внешнего мира). Все данные что хранятся внутри, внутри же и обрабатываются. Общение с внешним миром - запрос-ответ. Причем, запрос содержит набор критериев, ответы все достаточно короткие.

Если говорить про protobuf - ну это все основано на давно известном принципе датаграммного обмена. Только накрутили универсальности в ущерб производительности. В наших задачах, опять же, не требуется - что отправитель, что получатель всегда знает точно какой набор данных ему придет и в какой структуре. Т.е. описали структуру, заполнили, отдали в канал. Там ее получили и сразу с ней работают как есть. Минимальные накладные расходы, максимальная скорость и ресурсоэффективность. Я этими делами баловался еще черт знает сколько лет назад когда был в разработке системы мониторинга инженерного оборудования зданий - там связи между промконтроллерами и микроядром (которое я делал) и микроядром и интерфейсными клиентами осуществлялась именно датаграммами. Структура и размер смысловой части сообщения задавалась кодом в заголовке датаграммы. Дальше диспетчер по коду уже отдавал нужному обработчику который знал что со всем этим делать. Неизвестный код отправлялся в помойку сразу - "мы не знаем что это такое и не знаем что с этим делать").

Здесь примерно также, только в качестве транспорта используется очередь.

Тут еще вопрос надежности.

Тут мейнфремы проигрывают катастрофически. Когда у Вас кластер размазан по нескольким ЦОД по окружности всего земного шарика, то Вам ни пожар, ни землетрясения, ни наводнения не страшны.

И цены.

С этим тоже все не в пользу мэйнфремов. Стоимость закупки еще сравнима, а вот со стоимостью владения - уже беда. Крупносерийное производство и конкуренция из-за унификации всегда дешевле. К тому же более мощное оборудование всегда нелинейно дороже. Возьмите даже серверные блоки питания. При увеличении мощности в два раза цена вырастает в 4-5 раз.

При горизонтальном масштабировании Вам нет никакого смысла переплачивать за высочайшую надежность. Берете типовые сервера с дешевыми Xeon/EPYC и совершенно не волнуетесь, зная что даже если половина сдохнет, то система останется работоспособной.

У нас сейчас 120 8-поточных ядер Power9

А у меня сейчас на стенде разработки 16384 ядра на спарке А100. И что из этого? Вот закончу обучение модели, отдам следующим на очереди )))

Вы же должны отлично понимать, что сейчас, когда даже на бытовых CPU 64 ядра вполне доступны, ядра большой ценности не имеют. В кластере k8s их можно наращивать сотнями. Проблема в архитектуре, которая должна ложиться на k8s. Разработка такой архитектуры с нуля - не проблема. А вот переписывание уже имеющегося монолита - годы.

Можно пример где и зачем это может понадобится?

Да меня подобными запросами по грузовым перевозкам регулярно засыпают. Не поверите, но ПСДЦ именно от столь странных критериев и зависит. Все надеюсь это все же на ML перевести. Пусть уж лучше модель мучают, а не моих разработчиков. Но тут терабайт 40 нужно будет перелопатить.

Я не исключаю, что банки тоже хотят столь высокую гибкость при работе с клиентами, но осознают, что на имеющихся мейнфремах такие задачи не решаемы. Тут уже нужна горизонтально распределенная инфраструктура из сотен, если не тысяч узлов.

У нас я таких задач не могу себе представить. У нас есть набор атомарных сущностей - клиент, счет, карта, клиентские данные (которые тоже суть набор - ДУР, ФИО, ДР и т.п.) Их очень много, но нет ни одного бизнес-процесса, который использовал бы их все.

Подозреваю, что Вы об этом просто не знаете. Многие банки устанавливают лимиты по кредитным картам, суммы кредитов и ставки по ним именно агрегируя совсем не тривиальным образом всю эту и далеко не только эту информацию.

Даже размеры банковских комиссий могут нетривиально зависеть от исторических данных за разные периоды.

Почитайте про data mining на досуге. Когда данных много, то в них всегда есть "ранее неизвестные, нетривиальные, практически полезные и доступные интерпретации знания, необходимые для принятия решений в различных сферах человеческой деятельности"

Запихать все в одну запись? Это нерационально и снижает производительность.

А это при чем? Почему мы вдруг перешли к вопросу вертикального партиционирования (по столбцам)? К тому же для columstore такой подход почти всегда рационален и повышает производительность.

Асинхронная работа тут тоже ни к чему.

Мы будто на разных языках говорим или Вы мыслите исключительно с точки зрения однопоточного DOS. Вы же сами писали о наличии у Вас 120 ядер! Значит пока СУБД формирует следующую запись в потоке, предыдущую можно обрабатывать параллельно. Тем более, когда в алгоритме запросов к БД несколько и их вообще можно выполнять параллельно. Даже в Вашем случае, пока выполняется запрос по операциям по номеру карты вполне можно параллельно получить персональные данные. А получив список счетов клиента сделать параллельно запросы разным типам счетов, так как они связаны с разными данными.

Вы же сами писали, что некоторые запросы у Вас выполняются минуту. Значит, если их распараллелить хотя бы на 8 потоков, то они выполнятся уже за 8 секунд, что весьма заметно для пользователя. Я уже указывал выше, что встроенный параллелизм БД тут сильно проигрывает, так как очень мало знает о семантике извлекаемых данных. В отличии от разработчика.

Бизнес-процесс работает в отдельном задании

Тем более. Не по одной же записи запрашивается? Я же видел в Альфа-капитале когда-то при внедрении, сколько информации отображается на один запрос по банковским операциям. Уже тут передавать их клиенту можно параллельно с их извлечением из БД.

Опять же - что может сподвигнуть на создание терабайтных записей?

Какая разница? Да хоть история операций крупного клиента более, чем десятилетней давности, начиная с 1860 года!

Ну если Вас смущают терабайты, то пусть, как у меня, будут сотни мегабайт в массиве композитного типа.

Да даже мегабайт под буфер - уже расточительство! Большинство СУБД обходятся не более, чем десятком килобайт.

Вы все время увиливаете от ответа, пытаясь сказать, что лично Вам это мол не нужно. А я настойчиво пытаюсь заставить Вас взглянуть шире и увидеть, что это нужно, но имеющийся инструмент не способен решать такую задачу эффективно.

Или RPG/DB2 действительно столько неприспособленных к данным переменной и неопределенной длины?

Библиотеки, реализующие работу с БД, типы данных которые есть в БД, но нет в языке и т.п.

Расшифруйте "и т.п", так как остальное предоставляется производителем БД готовым, и разработчика очень мало заботит.

В языке - никак.

Спасибо! То есть RPG совершенно не пригоден в современных реалиях, когда ядер много и они дешевые.

Общение с внешним миром - запрос-ответ. Причем, запрос содержит набор критериев, ответы все достаточно короткие.

Тогда вообще непонятно, зачем тут мэйнфрем? Данные должны элементарно шардироваться. А от тяжелых аналитических запросов Вы открещиваетесь. Вы уж простите, но у того же Ozon клиентов больше, чем у Вас, в пике около 100 тыс. операций в минуту, 35 петабайт данных и все благополучно работает на шести тысячах дешевых типовых серверах. А ведь у него весьма сложная логистика, что требует немало ресурсов.

Если говорить про protobuf - ну это все основано на давно известном принципе датаграммного обмена. Только накрутили универсальности в ущерб производительности.

Пруф? Мы активно используем сейчас gRPC и уверенно могу утверждать о том, что конкурировать с Protobuf по производительности сейчас некому. Есть более бинарные протоколы немного более быстрые, в случае необходимости извлечения из сообщения менее половины полей, но имеющие проблемы со стабильностью и поддержкой.

Я же предоставил Вам доказательства, что только на простой компрессии чисел, можно получить прирост производительности в разы. Еще раз, распаковать сто раз два байта в 64-битный операнд в регистре в разы быстрее, чем считать в кеш CPU из RAM лишние 600 нулевых байт.

Поймите, мир изменился. Если 20 лет назад скорость обмена с RAM еще была сравнима со скоростью обработки данных CPU, то теперь разница уже на порядки.

96 ядер (192 потока) EPYC 9004 даже с 12 каналами (768 бит) выдающими около 300 ГБ/c, в пересчете на один поток, способный пережевать суммируя около 40 ГБ/c 64-битных целых чисел, выглядят очень бледно. Видно, что даже восьмикратное сжатие int64 в стиле Protobuf или MS SQL, на целочисленных операциях по прежнему упрется в шину памяти. Если часть из этих 12 каналов используется для организации NUMA, то ситуация усугубляется.

Тут мейнфремы проигрывают катастрофически. Когда у Вас кластер размазан по нескольким ЦОД по окружности всего земного шарика, то Вам ни пожар, ни землетрясения, ни наводнения не страшны.

Зато страшны проблемы с линиями связи. Которые случаются чаше чем пожары и наводнения. И которые находятся вне вашей зоны ответственности.

И если кто-то на другом конце шарика вдруг решит что вы себя неправильно ведете, то можете лишиться пары-тройки ЦОД-ов.

Хранение данных "где-то там" - это рычаг давления на вас.

Увы, но такова ситуация.

Проблема в архитектуре, которая должна ложиться на k8s

Вот на последнем митапе был доклад про Power10. Суть такая - у вас есть машинка 30-ю ядрами и сколько-то там терабайт памяти. Вам ее становится мало, в покупаете еще одну, подключаете ее к первой тем же PowerAXON и получаете машинку с 60-ю ядрами и х2 терабайт памяти. Мало? Еще одну... При этом для "пользователя" это будет как одна машина. Никаких дополнительных действия по конфигурации софта делать не требуется. Возможности расширения - сотни, если не тысячи "машинок". И это уже даже не кластер в привычном понимании. Это примерно как воткнуть процессор в свободный сокет на материнке и еще пару-тройку планок памяти.

Многие банки устанавливают лимиты по кредитным картам, суммы кредитов и ставки по ним именно агрегируя совсем не тривиальным образом всю эту и далеко не только эту информацию.

А это не задача АБС и не те проблемы, которые решаются на центральных серверах. И даже не mission critical задача. Посему она вынесена на одну из внешних систем. А уж что там работает - я не в курсе.

Мы будто на разных языках говорим или Вы мыслите исключительно с точки зрения однопоточного DOS

Это вы мыслите в рамках DOS и одного инструмента где все приходится делать руками.

Здесь же очень многое делается системой. Если нужно что-то делать параллельно - оно будет выполняться параллельно в другом фоновом задании. Именно задании. К этому надо привыкнуть, сразу может не зайти.

Вы все время увиливаете от ответа, пытаясь сказать, что лично Вам это мол не нужно. А я настойчиво пытаюсь заставить Вас взглянуть шире и увидеть, что это нужно, но имеющийся инструмент не способен решать такую задачу эффективно.

И при этом не можете привести ни одного конкретного примера из реальной жизни.

Ну если Вас смущают терабайты, то пусть, как у меня, будут сотни мегабайт в массиве композитного типа.

Еще раз - конкретный пример из жизни увидеть хочется. Именно того, когда вы в ответ на конкретный запрос получаете кучу данных, структура которых вам заранее неизвестна.

Ну давайте я вас буду убеждать что все вот это ваше - полная фигня и сетевая модель БД (приходилось работать? мне - да) с ее сущностями такие как "набор, "адрес записи в БД" намного производительнее.

Даже в Вашем случае, пока выполняется запрос по операциям по номеру карты вполне можно параллельно получить персональные данные.

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

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

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

В задании работает то, что невозможно распараллелить в силу специфики задачи.

Условно говоря - вы не можете уменьшить остаток на счете до того, как не убедитесь что платеж прошел (да, сумма ставится на холд, но это не уменьшение баланса, это холд на который будет уменьшен баланс после того как платеж пройдет).

А чтобы пропустить платеж, нужно провести ряд операций в рамках контроля платежей.

Аналогично - дата актуализации клиента не может быть обновлена до тех пор, пока не будет пройден ряд проверок.

Или RPG/DB2 действительно столько неприспособленных к данным переменной и неопределенной длины?

Реализовать можно, но в наших приложениях я с такими задачами не сталкивался.

Повторюсь - банк - суть очень сложный механизм. Состоящий из множества систем, каждая из которых выполняет свою функцию. Аналитические запросы - это не задача АБС. Они есть, но реализуются совсем в других местах, на других системах и другими инструментами.

Простейшая аналогия - вы пытаетесь найти пилу, которой будет одинаково удобно раскраивать листовой материал, делать тонкий фигурные резы, валить деревья и пилить дрова. И пытаете всех убедить что это единственно правильный подход. Мы же просто для каждой задачи используем наиболее подходящий инструмент. Даже в рамках нашей системы что-то пишется на RPG, что-то - на С/С++. А что-то вообще на CL или непосредственно на SQL (который может запускаться как самостоятельный запрос со своими внутренними переменными, процедурами и т.п.)

Вопрос исключительно в производительности и удобстве.

То есть RPG совершенно не пригоден в современных реалиях, когда ядер много и они дешевые.

Вы всерьез полагаете, что все что работает на центральном сервере суть одна большая программа на RPG, работающая в одном задании?

Вы уж простите, но у того же Ozon клиентов больше, чем у Вас, в пике около 100 тыс. операций в минуту, 35 петабайт данных и все благополучно работает на шести тысячах дешевых типовых серверах.

А теперь скажите - что будет если Озон продаст зарядник для телефона какому-нибудь бинЛадену? Его закроют? А если при оформлении покупки у клиента выскочить "ой, что-то пошло не так, попробуйте позже" - придет регулятор и выпишет штраф с многими нулями? А если вдруг аккаунт клиента "съедет" - что будет?

Да ничего. Это не банк. Там при регистрации клиента его не будут проверять по спискам террористов-экстремистов. Там никто не будет следить что у него срок действия паспорта закончился и блокировать аккаунт, высылая предупреждение за установленное количество дней. Там никто не будет контролировать каждый платеж по 100500 параметрам.

Там "зоопарк" задач совершенно другой и цена ошибки совершенно другая. И другие требования к надежности, доступности систем и т.п. Там даже время недоступности системы не нормируется регулятором (и вообще - есть ли там регулятор вообще)?

Хотите сравнивать? Сравнивайте с чем-то посерьезнее. Например, контроль АЗ АЭС где нужно в реальном времени обрабатывать информацию от десятков тысяч датчиков и мониторить распределение плотности нейтронных потоков по АЗ (и еще пару десятков разных параметров), вынося решения по управлению реактором. Ошибся? Ну на тебе еще один Чернобыль (именно это там и было, кстати)...

И попробуйте такую задачку раскидать "по дешевым серверам в нескольких ЦОД по всему шарику".

Тут, конечно, не АЭС, но и не интернет-лабаз.

Я же предоставил Вам доказательства, что только на простой компрессии чисел, можно получить прирост производительности в разы. Еще раз, распаковать сто раз два байта в 64-битный операнд в регистре в разы быстрее, чем считать в кеш CPU из RAM лишние 600 нулевых байт.

Речь не о распаковке. Речь о том, что для начала нужно каждый раз понять - а нужно его распаковывать? Это инт, дабл или вообще строка? И так с каждым операндом.

Зато страшны проблемы с линиями связи.

Но для мейнфрема они намного страшнее, чем для распределенной системы. В первом случае падение только одной линии связи приводит к полному выходу из строя, в во втором для выхода из строя требуется одновременно падение свыше половины линий связи.

И если кто-то на другом конце шарика вдруг решит что вы себя неправильно ведете, то можете лишиться пары-тройки ЦОД-ов.

Ну да. И если с мейнфремом у Вас всего один ЦОД, то лишитесь вообще всего, тогда как распределенная система в десятках ЦОД этого даже не заметит.

Хранение данных "где-то там" - это рычаг давления на вас.

Вы их всегда храните "где-то там", а не в чипе вживленном Вам в голову. С мэйнфремом в одном месте, без него - во множестве мест. К тому же "рычаг давления" так себе. Переезд из ЦОД в ЦОД - совершенно обычное явление и штатная процедура без всяких "рычагов", только ради коммерческой выгоды и слабо влияющая на доступность сервисов, при наличии еще хотя бы пары площадок.

Можете хотя бы страну назвать, которая столь ничтожно мала, что по ее территории бессмысленно делать распределенную сеть ЦОД и при этом столько политически активна, что боится использовать ЦОД за рубежом? КНДР? Но она далеко не маленькая, да и может, не опасаясь политических проблем при ведении бизнеса, пользоваться ЦОД в Бразилии, Венесуэле, Египте, ОАЭ, Индии, РФ, Китае и т.п. - по всем земному шарику.

Речь ведь явно не про РФ, где только в Москве массово пользуются одновременно 3-5 ЦОД в разных округах для повышения доступности сервисов.

Если взять упомянутый ранее Альфа-банк, то при его количестве отделений по стране, только в них можно разместить буквально по одному серверу в стойке, получив на один-два порядка большую производительность, чем на мэйнфрейме и на те же один-два порядка повысив доступность, особенно для регионов. Знаю о чем говорю, так как раз к Альфа-банку много претензий из-за медленного обслуживания в региональных отделениях по техническим причинам. У меня в Петропавловске-Камчатском, однажды, только персональную информацию загружали с Вашего любимого мэйнфрема в Москве минут 20! Даже 100 миллионов клиентов - это копейки без детализации операций и вполне могут быть реплицированы чуть ли не в каждое отделение.

Вот на последнем митапе был доклад про Power10

подключаете ее к первой тем же PowerAXON и получаете машинку с 60-ю ядрами и х2 терабайт памяти. Мало? Еще одну... При этом для "пользователя" это будет как одна машина.

Похоже это была какая-то рекламная акция и Вас сильно ввели в заблуждение. PowerAXON дает задержку до 100 нс при обращении к памяти второй машины в кластере. Это очень много. 10МГц даже против десктопных 400МГц - катастрофически мало.

Возможности расширения - сотни, если не тысячи "машинок".

У POWER10 только 16 интерфейсов PowerAxon. То есть, свыше 16 машин получат задержки уже в районе 1 мкс и выше, что вообще лишает смысла использовать такую конфигурацию для монолитного приложения. Она имеет смысл только для приложений с глубоким параллелизмом, который монолит в принципе не поддерживает.

Тогда как для микросервисной архитектуры POWER10 смысла не имеет вообще. У меня только в зоне разработки текущего проекта 8,212 ядер и 9.3ТБ памяти, а всего в сумме 25136 ядер и 29.91 памяти. Это не считая 16384 ядра CUDA. Тут, впрочем, затесалось еще 160 ядер ARM, но это на стадии НИОКР, так как выявились определенные проблемы с Java.

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

Вот видите, для того, чтобы отобразить операционисту на экране всю информацию по клиенту пришедшему в отделение, Вам приходится порождать минимум два задания, тогда как в микросервисной архитектуре это будет одно многопоточное задание, что требует раза в два меньше ресурсов и сократит сетевой обмен между региональным отделением и ЦОД.

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

И там уже система сама решает как все это дело по ядрам-потокам раскидать.

По кругу ходим. Я уже писал, что по моим замерам явный параллелизм в коде выигрывает у встроенного параллелизма СУБД на порядок. И Вам это не изменить, так как разработчику семантика данных известна, а СУБД - нет. Причем к DB2 это относится даже в большей мере, чем к Oracle, MS SQL и PostgreSQL. Не обижайтесь, но оптимизатор там хреновый, особенно при построении параллельных планов запросов.

Вы почему-то параллелизм и асинхронность сразу сводите к многопоточности. Но это далеко не так. Клиентский процесс и клиент СУБД уже разные процессы. И ничто не мешает клиентскому процессу продолжать выполнение в том же потоке на своем ядре, пока СУБД на другом ядре выполняет полученный ранее запрос. То есть, несмотря на то, что Вы в коде можете породить вроде бы отдельную задачу, фактически, она вполне может выполниться в том же потоке во время выполнения асинхронных вызовов.

В задании работает то, что невозможно распараллелить в силу специфики задачи.

Может хватит? Я же уже на пальцах показал, что любое задание, считывающее более одной записи из БД, можно распараллелить, так как любое обращение к БД по сути своей всегда асинхронно. А любую запись хоть как-то, но нужно обработать.

Или на ваших хваленых суперсистемах все крутится в одном задании, а чтобы получить параллельность требуется создавать новые виртуалки и контейнеры?

Вы будто не читаете, что я пишу. Может я плохо объясняю? Ну почитайте, например, эти подробные объяснения. Может понятней будет?

В асинхронной модели потоки, в большинстве случаев, порождаются только при старте сервиса. Исключения редки, иначе они говорят о неправильной кофигурации пула потоков компилятором и/или средой выполнения. При получении запроса ("задания" в Вашей терминологии), используются уже созданные "рабочие", не загруженные в данный момент. Такой вот map/reduce для уже готовых к работе потоков. Это не только сокращает издержки на создание потоков но, что самое главное, позволяет операционной системе существенно сократить миграцию потоков с ядра на ядро. То есть такой подход позволяет наиболее эффективно использовать регистры CPU и L1/L2 кеш ядра. Но требует указания от разработчика, что следует выполнять асинхронно и к какому моменту результат этого асинхронного выполнения потребуется. Эта же модель вполне подходит даже для чисто вычислительных задач, когда явно указывается, какие вычисления можно выполнять в разных потоках. И тем более она чрезвычайно эффективна для задач, явно коммуницирующих с другими сервисами, как СУБД, или внешней средой.

Еще раз - конкретный пример из жизни увидеть хочется. Именно того, когда вы в ответ на конкретный запрос получаете кучу данных, структура которых вам заранее неизвестна.

Простейший пример с NULL полями я Вам уже приводил. Вы не знаете структуру записи в терминах языка программирования. Вы знаете какие поля в записи, какие из них могут быть nullable, битовую маску длиной равной количеству nullable полей, по которой видно, какие из них NULL и строку байтов переменной длины, содержащую последовательно запрошенные поля переменной длины, где NULL поля просто пропущены. То есть, Вы не можете определить в коде структуру, описывающую то, что получаете в каждой записи.

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

А теперь скажите - что будет если Озон продаст зарядник для телефона какому-нибудь бинЛадену? Его закроют?

Не надо заниматься демагогией. Заплатит штраф, так же как и банк. Все измеряется деньгами. И разнести Озон, так же, как когда-то ЮКОС или СанРайз, могут с таким же успехом, как и отозвать лицензию у банка. Но вот если после пожара логистическом центре с ЦОД(!) Озон лишь задержал доставку ряда товаров, то после пожара в Вашем ЦОД останется только закрывать банк. Нигерийский Zenith Bank пережил пожар только благодаря государственной поддержке. В Африке, видимо, до сих пор, как у Вас - монолит на одном кластере в одном месте )))

ВТБ еще три года назад объявил о переходе на микросервисную архитектуру. А еще в 2019 году ВТБ начал внедрять ARENADATA DB в качестве основной БД, что, если покопаться, оказывается доработанной GreenPlum на базе PostgreSQL. К 2021 году они завершили переход. В результате удалось добиться повышения скорости обработки в несколько раз и снизить общую стоимость владения платформой в 2 раза.

Вас не удивляет, что у НСПК уже десять ЦОД и более пяти тысяч серверов?

Если меня не читаете, то хотя бы коллег из банков почитайте!

Например, контроль АЗ АЭС

Хороший пример. РосАтом еще в 2014 начал переход на микросервисную архитектуру и PostreSQL. Мейнфремы у них изначально использовались только для Hana, что к АЭС имеет весьма отдаленное отношение. И от этого еще два года назад они ушли.

Речь не о распаковке. Речь о том, что для начала нужно каждый раз понять а нужно его распаковывать?

А зачем запрашивать из БД поля, которые не нужны? А уж способ их упаковки известен. В подавляющем большинстве случаев еще до посылки запроса к БД. В остальных случаях берется из метаданных рекордсета.

Это инт, дабл или вообще строка? И так с каждым операндом.

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

Почитайте вот про новые Power10

По тестам, они примерно соответствуют 64-ядерным Zen 3 и явно проигрывают не только 96, но и 64-ядерным Zen 4. У POWER10 очень маленький кеш, всего 120 МБ и всего 8 каналов к памяти. Если три-четыре года назад это и могло выстрелить, то сейчас выглядит бледно.

Читайте внимательно и вдумчиво. Особенно про NUMA, CAPI и PowerAXON - что это и зачем.

Ваши представления ограничены идеологией десктопов (пусть и в "серверном исполнении". Этаких "больших персоналок", которые можно как-то связать между собой и как-то заставить более-менее совместно работать, гоняя между ними байтики по сети.

Power10 - это уже идеология "кирпичиков" из которых вы строите один сервер той мощности, который вам нужен. А не несколько серверов (пусть и объединенных в кластер).

Вы вообще читаете, что я пишу? NUMA давно есть во всех серверных процессорах. К OpenCAPI AMD c Nvidia присоединились еще в 2016 году. PowerAXON больше заточен на межпроцессорное взаимодействие, поэтому остальные больше продвигают Hybrid NUMA, более подходящий для CUDA.

Power10 - это уже идеология "кирпичиков" из которых вы строите один сервер той мощности, который вам нужен.

Я выше Вам уже указал, что после того, как 16 каналов PowerAXON окажутся использованными на 16 процессорах, дальнейшее наращивание теряет смысл. Чего совсем не скажешь о кластерах, масштабируемых неограниченно.

Даже на десятке хостов он уже выглядит печально.

Есть два варианта масштабирования: горизонтальное и вертикальное. Вы думаете про первое, а мейнфреймы это ветка второго. Здесь хосты добавляют не снаружи, а внутрь. :)

Почитайте на досуге про это направление в IBM - реально отдельный мир, со своей терминологией, принципами и архитектурой. Например, в отличие от того же Unix, где все построено на файлах в директориях, там даже такого понятия раньше не было. Как такое может быть? Легко - они просто не нужны - у вас же есть доступ сразу к структурированным данным.

Есть два варианта масштабирования: горизонтальное и вертикальное. Вы думаете про первое, а мейнфреймы это ветка второго.

Вот только горизонтальное масштабирование безгранично, а вертикальное - совсем нет. И если в конце 90-х мейнфреймы еще продавались новым клиента, то уже в начале 2000-х - преимущественно только старым клиентам, уже подсевшим на эту архитектуру. Потому что горизонтальное масштабирование стало обеспечивать не только неограниченную производительность, но и намного более высокую надежность. Когда у Вас кластер размазан по нескольким ЦОД по окружности всего земного шарика, то Вам ни пожар, ни землетрясения, ни наводнения не страшны.

Почитайте на досуге про это направление в IBM

Зачем мне читать, если я сам начинал на мэйнфремах и писал программы на ассемблере, COBOL, PL/I и REXX до середины 90-х?

у вас же есть доступ сразу к структурированным данным

А это при чем? Я про неструктурированные данные ни слова не писал. Я писал о данных переменной или неопределенной длины. Вполне себе структурированные. Вот сериализованные данные я затрагивал, но тоже исключительно структурированные.

Зачем мне читать, если я сам начинал на мэйнфремах и писал программы на ассемблере, COBOL, PL/I и REXX до середины 90-х?

Что было в середине 90-х и что сейчас - две очень большие разницы.

Интересно, вы писали на ассемблере - работали в Рочестере? В команде разработчиков ядра AS/400? Ассемблер доступен только там. Выше SLIC - только MI (и то сейчас убрали MI компилятор, оставив только неполный набор С-шных оберток для них.

И если в конце 90-х мейнфреймы еще продавались новым клиента, то уже в начале 2000-х - преимущественно только старым клиентам, уже подсевшим на эту архитектуру

Ай-вэй... И исключительно для старых клиентов IBM регулярно выпускает новые процессоры и регулярно выпускает новые версии операционки?

Извините, не верю...

Этот рынок, конечно, нишевый, но он стабилен.

Что было в середине 90-х и что сейчас - две очень большие разницы.

И да и нет. Огромный груз легаси все равно остался. Я отслеживаю IT новости, так что в курсе.

В команде разработчиков ядра AS/400?

Вы искренне считаете, что это единственный мейнфрем у IBM? )))

Несмотря на громкое название High-Level, HLASM все равно ассемблер, хоть и с очень развитым макроязыком.

И исключительно для старых клиентов IBM регулярно выпускает новые процессоры и регулярно выпускает новые версии операционки?

Естественно. А куда деваться от легаси? Дешевле купить более мощный мейнфрейм, чем переписать миллионы строк на COBOL, если не на ассемблере. А объемы обрабатываемых данных то растут.

В 2020 году средний возраст мейнфрейма в эксплуатации составил 17 лет! Это уже самые настоящие динозавры )

Несмотря на огромные рекламные вливания, в прошлом году выручка IBM от продажи мейнфремов рухнула на 30%. Впрочем подобные падения она переживала и в 2014 и в 2016 году, после чего с 2019 по 2021 показывала рост на 3-5%, на основании чего в 2022 году и возникли очень радужные прогнозы. Прошлый год показал, что никаких оснований для них не имеется.

А если Вы в РФ, то вообще все ясно. До 2030 года Вам все равно потребуется отказаться от AS/400, так как вероятность приостановления блокировки сертификата ФСТЭК для неё ничтожна, и нет возможности ее использовать вообще без персональных персональных данных.

Про то, что рынок мейнфреймов в РФ в 2022 рухнул на 95% и подниматься не собирается, Вы точно в курсе. А вот про то, что уже 60% владельцев мейнфреймов в РФ заняты проектами по отказу от них в пользу распределенных кластеров - похоже, что нет. Все же легаси, по объективным причинам, в РФ заметно меньше, чем за рубежом.

Что делать, миром правит бабло. И если появилась техническая возможность вместо дорогого синьора на RPG и DB2 использовать дешевого джуна на Java/C#/Python с ORM, ценой однократной покупки дополнительного блейда, стоимость которого сравнима с месячной зарплатой синьора, то так и будет сделано. Ничего личного, просто бизнес.

Если вам нужен условный звездолёт, то хоть сотня, хоть тысяча велосипедов - так себе альтернатива.

Горизонтальное масштабирование ведёт к кратному увеличению стоимости обслуживания такой инфраструктуры. Появляются дополнительные проблемы в плане физической безопасности. Ну и CAP теорема встаёт во весь рост, что делает решение архитектурной задачи сложнее на порядок. Вы же выше сами писали - базы, сети, Java.. Представляте себе платёжку, согласование балансов которой, должно осуществляться между несколькими дата центрами, раскиданными по всему материку? Вам нужно погасить кредит, но платеж не проходит потому, что один из ДЦ где-то в тайге прилёг отдохнуть. Так что банкам это ещё ни один раз икнется.

Механика санкций не столько в том, чтобы отрезать от остального мира. Они вынуждают нести значительные дополнительные издержки при решении типовых задач. А дальше все само развалится.

Если вам нужен условный звездолёт, то хоть сотня, хоть тысяча велосипедов - так себе альтернатива.

Но если мне не нужен звездолет, а нужно исследовать Проксиму Центавра, то сотни мелких парусников - отличная альтернатива.

Горизонтальное масштабирование ведёт к кратному увеличению стоимости обслуживания такой инфраструктуры.

Не понял к чему это. При горизонтальном масштабировании рост стоимости владения действительно линейный. Во сколько крат нарастили мощность, во столько же возросла стоимость владения. Но при вертикальном масштабировании рост стоимости экспоненциальный.

Представляте себе платёжку, согласование балансов которой, должно осуществляться между несколькими дата центрами, раскиданными по всему материку?

Так работает любой процессинговый центр, в том числе и НСПК. Платежка проходит ЦОД плательщика, один из десятка ЦОД НСПК, один из пяти ЦОД Центробанка и ЦОД получателя.

Что Вас смущает? Баланс - это лишь агрегат, а не вся история операций. Почему, например, ОПСОСы могут оперативно реплицировать баланс абонентов между тысячами сот, а банки не в состоянии это сделать между десятком ЦОД?

Вам нужно погасить кредит, но платеж не проходит потому, что один из ДЦ где-то в тайге прилёг отдохнуть.

Вы все перепутали. Это сейчас, если единственный ЦОД недоступен, то ни один платеж не пройдет, а в распределенной системе - это не проблема. На срок таймаута задержатся только те платежи, которые в момент падения обрабатывал отказавший ЦОД. Судя по ссылке на CAP теорему, Вы забыли, что в реальной жизни Availability не бинарна, а измеряется временем доступа.

Механика санкций не столько в том, чтобы отрезать от остального мира. Они вынуждают нести значительные дополнительные издержки при решении типовых задач. А дальше все само развалится.

Вот только история показывает обратное. Из-за санкций ни разу еще ничего не развалилось. Разваливалось, наоборот, от активной "дружеской" помощи. Санкции эффективны, в первую очередь, против "дружественных" стран. Цели прекращения военных действий в случае враждебных стран с помощью санкций не удалось добиться ещё ни разу.

Мы даже на MS SQL уже получили море проблем из-за его UTF-16, в который тупо не влазят все возможные символы UTF-8, регулярно прилетающие из внешних источников. Как сейчас жить с однобайтовой кодировкой, когда даже официальные наименования встречаются с трехбайтовыми UTF-8 символами - вообще не представляю.

Вы не поверите, но банк с 50млн клиентов (и огромным количеством клиентских данных) и однобайтовой кодировкой на центральных серверах проблем не имеет.

Если это так на DB2, то я в шоке. Например, в PostgreSQL и длина, и значение являются динамическими массивами байт.

при чем тут БД? Это программа, которая работает в памяти. И в н языке тип varchar имеет вполне определеннее представление в памяти. И это не динамическая строка.

Как физически лежит ваш массив в БД? На диске? Динамический?

Я писал уже - вся эта "динамичность" при интенсивном использовании дает просадку по производительности. Ощутимую такую просадку.

Размер данных ограничивается при сборке по умолчанию 1ГБ, но при желании перекомпиляцией может быть увеличен вплоть до 32 ТБ.

Вы работаете со строками 32ТБ? varchar - это строковый тип данных.

Для больших объектов вообще-то есть BLOB/CLOB

Это такое издевательство от IBM? В XXI веке имена короче 30 символов (до 120 байт в UTF-8) - выглядят именно так.

Это ваша точка зрения. На самом деле никаких проблем тут нет.

Иными словами, она просто отсутствует, что увеличивает трудоемкость разработки.

Чем именно?

Буфер на одну запись? Не слишком ли жирный расход памяти?

Буфер куда копируется очередная запись выборки. Ну или несколько записей.

Кстати, асинхронности я тут тоже не заметил. Или RPG не позволяет через async/await обрабатывать данные пока СУБД выполняет очередной запрос?

Это лишено смысла в тех задачах, которые мы решаем. Что оно должно делать пока выполняется запрос? Пока нет данных для обработки...

Суть всех задач у нас - сформировать поток данных и что-то с ними сделать. Асинхронка работает хорошо, когда у вас кроме этого есть еще чем заняться. Иначе вы будет просто асинхронно ждать появления очередной порции данных.

В Java/C# вообще не приходится задумываться о БД в этом случае. Сразу if или лямбда.

if к чему? Напишите (не думая о БД) условие - "если сумма депозитов в рублевом эквиваленте для всех счетов клиента не выше заданной, то..." Как вы это реализуете без обращения к таблице счетов, таблице валют и т.п.?

Ну или вот такое (из реального)

Получить список владельцев и держателей карт для обработки по следующим условиям:

  • Владелец не является держателем

  • Дата окончания действия карты больше текущей бизнес даты

  • Статус карты входит в список: 00, 01, 02, 03, 14, 16

  • Вид карточного контракта относится к ФЛ

  • Код контракта начинается на ‘P’

Ну и там еще 3-4 блока подобных... Как вы это напишете на if и лямбдах без привязки к БД?

И да. Это только один из десятков тысяч процессов. И в каждом свои условия и своя бизнес-логика.

SQL начинается только на сложных запросах, где тот же linq катастрофически тупит при построении SQL запроса

Вот именно. Тупит. Потому что это не часть языка, а надстройка над ним.

А простых запросов у нас не бывает.

Доступ к кортежу и его полям через методы выглядит намного эффективней и удобней, чем предварительное прибивание гвоздями структуры данных в памяти к кортеж

А ничего что вызов метода - это образование как минимум одного уровня стека (а обычно и не одного)? Которое тоже не бесплатно...

типы полей обрабатываются автоматически

И, конечно же, это абсолютно не занимает времени. Ага, щаз...

Прогнать ваш код через наш PEX (Performance EXplorer) - вам бы вагон претензий вывалили бы. По поводу лишних вызовов, 100500 уровней стека и т.п.

Вообще у меня сложилось впечатление, что на RPG, например, отпарсить сообщения protobuf из логов в БД - легче повеситься.

А он не для этого :-) Это не язык общего назначения. Он сделан для вполне конкретных целей.

Я не знаю что вы там парсите (видимо, у вас логи в тексте хранятся - каменный век, извините).

У нас есть joblog, есть очереди сообщений. Все они хранятся в специальных форматах. Смотреть их можно как в терминале командой WRKJOBLOG (или WRKMSGQ) или SQL запросами

1	INFORMATIONAL	2024-02-19 08:33:42.603956	QSYS	QWTPIIPP	Задание 396596/QUSER/QZDASOINIT запущено 19.02.24 в 08:33:42 в подсистеме QUSRWRK в библиотеке QSYS. Задание появилось в системе 19.02.24 в 08:33:42.	
2	INFORMATIONAL	2024-02-21 18:26:42.566683	QSYS	QWTCHGJB	ACGDTA для 396596/QUSER/QZDASOINIT не занесен в журнал, код причины 1.	&N Причина . . . . :   Данные Задание учета ресурсов задания 396596/QUSER/QZDASOINIT не были занесены в журнал учета ресурсов системы с именем QSYS/QACGJRN. &P -- Коды причин и их значения приведены ниже: &P -- 1 - Системное значение уровня учета ресурсов (QACGLVL) указывает, что выполнять учет ресурсов этого уровня при входе задания в систему не нужно. &P -- 2 - Журнал QSYS/QACGJRN не в состоянии принимать данные.  Данные учета ресурсов были отправлены в протокол хронологии (QHST) в тексте сообщения CPF1303. Действия по исправлению см. в сообщении CPF1302 протокола хронологии (QHST). &P -- 3 - Журнал учета ресурсов QSYS/QACGJRN был выделен другому заданию.  Данные учета ресурсов были отправлены в протокол хронологии (QHST) в виде текста сообщения CPF1303.
3	INFORMATIONAL	2024-02-22 15:16:11.507446	QSYS	QWTCHGJB	ACGDTA для 396596/QUSER/QZDASOINIT не занесен в журнал, код причины 1.	&N Причина . . . . :   Данные Задание учета ресурсов задания 396596/QUSER/QZDASOINIT не были занесены в журнал учета ресурсов системы с именем QSYS/QACGJRN. &P -- Коды причин и их значения приведены ниже: &P -- 1 - Системное значение уровня учета ресурсов (QACGLVL) указывает, что выполнять учет ресурсов этого уровня при входе задания в систему не нужно. &P -- 2 - Журнал QSYS/QACGJRN не в состоянии принимать данные.  Данные учета ресурсов были отправлены в протокол хронологии (QHST) в тексте сообщения CPF1303. Действия по исправлению см. в сообщении CPF1302 протокола хронологии (QHST). &P -- 3 - Журнал учета ресурсов QSYS/QACGJRN был выделен другому заданию.  Данные учета ресурсов были отправлены в протокол хронологии (QHST) в виде текста сообщения CPF1303.
4	INFORMATIONAL	2024-02-22 15:16:11.507716	QSYS	QZBSSECR	К серверу подключен пользователь Y2KU с клиента 10.0.67.234.	&N Причина . . . . :   В данный момент с этим заданием сервера связан пользовательский профайл Y2KU с клиента 10.0.67.234.  Имя клиента - это имя удаленной системы TCP/IP, IP-адрес этой системы в десятичной записи с точками, адрес IPv6 либо имя локального хоста.
5	COMPLETION	    2024-02-22 15:16:11.953856	QSYS	QWTCHGJB	Задание 396596/QUSER/QZDASOINIT изменено пользователем Y2KU.	
6	INFORMATIONAL	2024-02-22 15:16:11.989491	QSYS	QZDASRV	    Следующие специальные регистры были заданы: CLIENT_ACCTNG: Windows 10;SSL=false;admin_user=true, CLIENT_APPLNAME: IBM i Access Client Solutions - Run SQL Scripts, CLIENT_PROGRAMID: file:/C:/Users/victo/IBM/ClientSolutions/acsbundle.jar | Версия: 1.1.8.8 | ИД компоновки: 1380 | 2021-09-13 13:47:59, CLIENT_USERID: victo, CLIENT_WRKSTNNAME: VPOMHP	&N Причина . . . . :   Это сообщение отправлено когда любой из клиентских специальных регистров был обновлен.

И ничего не надо парсить.

И да. Java и С/С++ у нас тоже есть и используются там, где это эффективно и целесообразно. При этом они прекрасно стыкуются с RPG на уровне ABI.

Вы не поверите, но банк с 50млн клиентов (и огромным количеством клиентских данных) и однобайтовой кодировкой на центральных серверах проблем не имеет.

Естественно не верю. Хотя бы потому, что уже не раз ругался с техподдержкой банков именно по этому поводу. Получая в ответ совершенно унизительные извинения со ссылкой на ущербные технические возможности и просьбой убедить контрагентов не использовать, например, диакритику и даже символы валют ¥ или

Я уже молчу о любви китайцев влепить назначение платежа своими иероглифами.

при чем тут БД?

При том, что Вашим же словам, она не умеет эффективно обрабатывать VARCHAR, в отличии от того же Oracle, MS SQL или PostgreSQL, где VARCHAR в подавляющем большинстве случаев эффективней CHAR.

Как физически лежит ваш массив в БД? На диске? Динамический?

Логически, да. Не забывайте про страничную организацию памяти (оперативной и дисковой) и huge pages.

Я писал уже - вся эта "динамичность" при интенсивном использовании дает просадку по производительности. Ощутимую такую просадку.

Вот именно. Потому я и в шоке. Так как в остальных БД не только динамические структуры, но даже компрессия, превращающая данные фиксированной длины в переменной длины, уже приводит к заметному росту производительности. Почитайте, например: https://www.mssqltips.com/sqlservertip/3187/demonstrating-the-effects-of-using-data-compression-in-sql-server/

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

К слову, алгоритм компрессии MS SQL весьма похож на упомянутый мной protobuf. https://learn.microsoft.com/en-us/sql/relational-databases/data-compression/row-compression-implementation?view=sql-server-ver16

Вы работаете со строками 32ТБ? varchar - это строковый тип данных.

Пока не приходилось. Но сотни мегабайт - уже не редкость. Как упрусь в лимит по умолчанию в 1 ГБ, потребуется переходить на перекомпилированный PostgreSQL.

Для больших объектов вообще-то есть BLOB/CLOB

Они весьма неэффективны, если содержимое может варьироваться от нескольких байт до сотен мегабайт. В том же PostgreSQL они deprecated уже очень давно. В MS SQL - 18 лет.

Буфер куда копируется очередная запись выборки.

Вот я и спрашиваю, откуда известно, какой размер записи? Даже если в ней VARCHAR без constraint она уже может быть сотни мегабайт. И тем более, если в ней массив композитного типа, который может быть вообще любого размера. Как выделить буфер на всю запись, если её размер, в общем случае, неизвестен?

Это лишено смысла в тех задачах, которые мы решаем. Что оно должно делать пока выполняется запрос? Пока нет данных для обработки...

Вы прикалываетесь? Это верно только если вся программа обрабатывает только одну запись. В случае нескольких записей асинхронность уже приводит к заметному росту производительности, так как пока обрабатывается предыдущая запись, считывается следующая. Тем более, если речь идет о случае множества запросов к БД, часть из которых требует данных из предыдущих запросов, а часть нет. Тогда необходимо явное указание в коде, в какой момент нам уже нужны результаты ранее посланных запросов к БД, чтобы дождаться их, если они еще не доступны. У меня так даже отчеты десятки асинхронных запросов одновременно к БД посылают, чтобы добиться высокой производительности. По сравнению со встроенным параллелизмом, выигрываю, порой, на порядок.

Как вы это реализуете без обращения к таблице счетов, таблице валют и т.п.?

Например, на Linq так. При этом задача кеширования обращений к БД лежит на нем.

Получить список владельцев и держателей карт для обработки по следующим условиям:

Простите, но это вообще элементарно. Вот когда условий становится под сотню, тогда уже приходится думать, что положить в columnstore, а что оставить в rowstore.

А простых запросов у нас не бывает.

Судя по предыдущему примеру, у нас очень разные представления о простых запросах. Для меня простой - это запрос из десятка-другого таблиц без сложных CTE/LATERAL/подзапросов. А вот запрос, на котором у меня когда-то валился DBEaver - уже можно считать сложным. Потому и оформлял его уже в виде VIEW.

Могу пояснить прямо по Вашему примеру:

  • Владелец не совершал более трех операций с кодами X, Y или Z в течении последних тридцати дней

  • Дата окончания действия карты больше текущей бизнес даты или меньше текущей даты, но по ней была не сторнированная операция продления срока действия в течении последних 365 дней

  • Медианное дневное значение остатка на счете за предыдущий год больше X.

  • Распределение сумм операций за последние 180 дней отличается от логнормального не более, чем на 20%

  • Время, прошедшее между последовательно совершенными операциями за последние три месяца, за исключением третьего квартиля, не превышает 10 дней

  • Владелец совершал за предыдущий год каждый календарный месяц, в котором больше 20 рабочих дней, не менее двух операций с кодами A, B или C.

  • Ну и дальше в том же духе )

Вот на таком Linq уже вряд ли эффективно запрос построит, так как плохо соображает в оконных функциях, и потребуется полчаса на написание запроса руками.

А ничего что вызов метода - это образование как минимум одного уровня стека (а обычно и не одного)? Которое тоже не бесплатно...

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

И, конечно же, это абсолютно не занимает времени.

Занимает, но только во время компиляции. Но уж никак не во время выполнения. Выше я уже писал, что сокращая в разы поток между кешем CPU и RAM, можно существенно выиграть в производительности. Только на распаковке небольших сумм в int64, когда они фактически в памяти занимают 1-2 байта, выигрыш может составить в три-четыре раза.

Я не знаю что вы там парсите (видимо, у вас логи в тексте хранятся - каменный век, извините).

Я же явно указал, что логи хранятся в БД. Что-то в CH, что-то в timescaledb. И почему вдруг RPG не положено парсить то, что лежит в БД - загадочно. У нас абсолютно нормально, когда из сообщения пришедшего от внешней системы извлекается только оперативная информация, а не оперативная информация, агрегаты и кроссвалидация обрабатываются уже потом.

И ничего не надо парсить.

Вы приводите пример, когда уже все отпарсено. Но, например, в случае АСКУЭ, когда к Вам валятся от концентраторов миллионы сообщений с десятками регистрами каждые пять минут, это непозволительная роскошь. Успеваешь выделять только наиболее критические события, пока сообщение в неизменном виде фиксируется в БД и дублируется в топик. Отслеживать, например, превышения мощности и реактивки за час/сутки/месяц приходится уже с задержкой в несколько секунд подписчиками кафки на другом кластере k8s.

банк с 50млн клиентов

Оставим даже в покое МосЭнергоСбыт. Лет десять назад на Камчатке, с каких то 100 тыс. абонентов и АСУКЭ раз в 15 минут, за месяц собиралось больше операций, чем у Вас за год. А так как у абонентов не по одному ПУ, а в ПУ несколько десятков регистров, то и размеры этих операций точно побольше банковских.

Сейчас железнодорожными перевозками занимаюсь, так в сутки по 200 миллионов операций прилетает суммарно на 30 ГБ. Впрочем про успешный переход РЖД с IBM Mainframe Parallel Sysplex и DB2 на k8s и PostgreSQL Вы наверняка слышали. Если еще в сентябре-октябре были проблемы производительностью, то сейчас система работает существенно быстрее, чем раньше. Вот еще CH внедрят для аналитики и исторических периодов - вообще красота будет.

Естественно не верю. Хотя бы потому, что уже не раз ругался с техподдержкой банков именно по этому поводу.

По какому именно?

В банках есть общепринятые в мире трехсимвольные коды валют. Используемые везде (в т.ч. и в SWIFT сообщениях) - RUR, USD, EUR и т.п. Есть еще трехзначные числовые коды (для рубля, например, 810). У нас, в частности, используются в 20-значном номере счета для обозначений валюты счета (7-8 позиции).

А эти значки - это бытовая инфографика, не более того.

Oracle, MS SQL или PostgreSQL, где VARCHAR в подавляющем большинстве случаев эффективней CHAR

А можете доказать это реальными цифрами? Ну скажем, статистики производительности и потребления ресурсов на выборках 50-100млн записей?

У нас такие исследования проводились. VARCHAR проигрывает.

Вот на таком Linq уже вряд ли эффективно запрос построит, так как плохо соображает в оконных функциях, и потребуется полчаса на написание запроса руками.

Это еще простенький запросец. Который вообще линеен, там пара-тройка джойнов и все.

Та же актуализация клиентов - там последовательно 5 выборок делается (пихать все в одну - просадка производительности). Тех, кого надо актуализировать. И там условий куда больше.

И SQL движок вполне адекватно справляется со всем этим.

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

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

Вы не можете заранее сказать что он отинлайнит, а что нет. И в любом случае это будет код, без которого мы обходимся. Совсем.

И почему вдруг RPG не положено парсить то, что лежит в БД - загадочно

Ну, наверное, потому что это специфический язык для специфических задач. Когда ничего не надо парсить - все уже разложено по полям.

Для иных задач я не стану натягивать сову на глобус, а возьму более подходящий для этого инструмент.

Сейчас железнодорожными перевозками занимаюсь, так в сутки по 200 миллионов операций прилетает суммарно на 30 ГБ.

Ну это примерно объемы наших платежей (только платежей!) за сутки. Разница в том, что каждый платеж должен пройти через систему контроля. И не зависнуть в ней даже на 10-15 минут (обычно платеж проходит в течении минуты по межбанку, внутри банка - секунды, но там контроль попроще для внутренних платежей). И при этом нельзя пропустить платеж тому, кому нельзя его пропускать (например, там еще много чего - только по линии комплаенса порядка 10-ти проверок). Иначе... Ну пределе - лишение лицензии.

Я не думаю, что вы проверяете свои грузоперевозки хотя бы по списками Росфина (от кого к кому) - а там сейчас навскидку тысяч 500 персонажей, да у каждого по несколько имен, адресов, документов и прочего.

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

В банках есть общепринятые в мире трехсимвольные коды валют.

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

А можете доказать это реальными цифрами? Ну скажем, статистики производительности и потребления ресурсов на выборках 50-100млн записей?

Чтобы приблизиться к реальности, я взял первую попавшуюся БД со справочником компаний и посчитал максимальную и среднюю длину полного наименования.

SELECT MAX(LENGTH(FullName)) AS MaxLen,
  AVG(LENGTH(FullName)) AS AvgLen
FROM SP_Company;

145 26.3934345479082321

Возьмем тогда для CHAR 145, а генерировать данные будем со средней длиной 27

CREATE TEMP TABLE _tmp_test_char AS
SELECT LEFT(MD5(RANDOM()::text)||MD5(RANDOM()::text),
   (RANDOM()*26*2+1)::int)::CHAR(145) AS SomeString
FROM generate_series(1,100000000) G(N);

SELECT AVG(LENGTH(SomeString))
FROM _tmp_test_char;

27.0017144500000000

SELECT pg_total_relation_size('_tmp_test_char');

18204450816

Аналогично поступаем с VARCHAR

CREATE TEMP TABLE _tmp_test_varchar AS
SELECT LEFT(MD5(RANDOM()::text)||MD5(RANDOM()::text),
   (RANDOM()*26*2+1)::int)::VARCHAR AS SomeString
FROM generate_series(1,100000000) G(N);

SELECT AVG(LENGTH(SomeString)) FROM _tmp_test_varchar;

27.0020831900000000

SELECT pg_total_relation_size('_tmp_test_varchar');

5993390080

Размер таблицы с VARCHAR получился в три раза меньше.

Теперь можно прочесать по очереди обе таблицы и, например, посчитать количество строк содержащих букву 'a'

EXPLAIN ANALYZE
SELECT SUM(CASE WHEN strpos(SomeString, 'a')=0
                THEN 0 ELSE 1 END)
FROM _tmp_test_char;

Aggregate  (cost=2800000.98..2800000.99 rows=1 width=8) (actual time=92713.094..92713.096 rows=1 loops=1)
  ->  Seq Scan on _tmp_test_char  (cost=0.00..2511111.99 rows=28888899 width=584) (actual time=0.025..13273.782 rows=100000000 loops=1)
Planning Time: 0.042 ms
Execution Time: 92713.120 ms

И то же самое для второй таблицы

EXPLAIN ANALYZE
SELECT SUM(CASE WHEN strpos(SomeString, 'a')=0
                THEN 0 ELSE 1 END)
FROM _tmp_test_varchar;

Aggregate  (cost=2472855.32..2472855.33 rows=1 width=8) (actual time=17890.014..17890.015 rows=1 loops=1)
  ->  Seq Scan on _tmp_test_varchar  (cost=0.00..1726609.04 rows=99499504 width=32) (actual time=0.040..7719.896 rows=100000000 loops=1)
Planning Time: 0.040 ms
Execution Time: 17890.038 ms

Как видим, VARCHAR выиграл более, чем в пять раз.

Это еще простенький запросец. Который вообще линеен, там пара-тройка джойнов и все.

Это Вы про 90 КБ запрос из 31 одной таблицы по моей ссылке? )))

последовательно 5 выборок делается (пихать все в одну - просадка производительности)

На PostgreSQL наоборот, если рекордсеты из CTE не требуют индексации, выгодней в одном запросе вставить в пару таблиц, обновить пару таблиц, да еще и выдать под конец результат.

Но тут следует учесть, что механизм временных таблиц в PostgreSQL сделан через одно место и им следует пользоваться только если уже вообще деваться некуда.

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

Вот такое на PostgreSQL не встречал. Были редкие случаи, когда пользовательскую функцию агрегации приходилось переписывать на Rust с plpgsql. Но там реально компиляция Rust в машинный код давала выигрыш, по сравнению с JIT компиляцией plpgsql.

Вы не можете заранее сказать что он отинлайнит, а что нет.

Во-первых, я могу это увидеть при компиляции и даже заставить инлайнить, если это действительно нужно. Во-вторых, на моей практике, GCC тут был намного чаще прав, чем мне казалось в начале.

Ну это примерно объемы наших платежей (только платежей!) за сутки.

Вот видите. Всего один небольшой проект, совсем крошечная часть бизнеса конгломерата СУЭК, НТК, ЕвроХим и СГК оказалась сравнима со всем бизнесом Вашего клиента )

Я не думаю, что вы проверяете свои грузоперевозки хотя бы по списками Росфина (от кого к кому) - а там сейчас навскидку тысяч 500 персонажей, да у каждого по несколько имен, адресов, документов и прочего.

Росфин тут точно не при чем, а вот по паспортам, естественно, вагоны отрабатываются. А это, порядка 1.3 млн. вагонов и у каждого, в среднем 2-3 паспорта. Про ремонты и осмотры так вообще молчу.

Но у меня задача совсем другая. У меня есть фактические операции с вагоном, на основании которых я должен предложить какие именно вагоны можно направить для конкретной грузоперевозки, и в каком количестве, если учитывать, что у каждого из них своя вероятность выйти из строя и попасть в ремонт, насколько вагон соответствует требованиям грузоотправителя (вот это как раз по паспортам). И самое веселое, нужно давать прогнозы времени промывки (если требуется), подачи, погрузки, рейса, разгрузки и отвода в соответствии с заданными пользователем рисками. Поэтому у меня не столько обработка операций с вагонами, сколько агрегаций с горизонтов до года при оперативной обработки и до 2018 года при переобучении модели прогнозирования. Собственно говоря, именно на основании этого возникает черновик ПСДЦ, если данная грузоперевозка вообще рентабельна. Таких заявок не перевозку вроде бы немного, всего ~30 тыс. ежедневно. Но если учесть, сколько вагонов в дислокации нужно рассмотреть, с точки зрения возможности и рентабельности их использования для каждой заявки, то перемалываются миллиарды строк. А так как заявки на перевозку конкурентные, то менеджеры по продажам услуг грузоперевозок могут поднять вой из-за задержки в несколько минут, после появления новой заявки. Ведь её может забрать себе конкурент.

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

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

А можете доказать это реальными цифрами?

Ради интереса покопался, почему в DB2 проблемы с NULL и VARCHAR. Как и ожидалось - опять из-за легаси. Огромное количество приложений, исторически, требуют указатель на кортеж фиксированной длины. И, хоть убейся, каждое поле в нем должно присутствовать. В первую очередь, это относится к COBOL. Вторая проблема - это обязательная фиксированная часть для полей переменной длины.

Для NULL это приводит к необходимости однобайтового индикатора NULL в каждом nullable поле, с сохранением самого поля с пустым значением в БД.

В PostgreSQL в одной 8К странице может содержаться 255 записей из 72 только NULL полей. Тогда как в DB2, в этой ситуации, каждое nullable поле, для примера, типа bigint будет занимать 9 байт. Page descriptor у DB2 потолще, чем у PostgreSQL в данном случае, так как он в последнем тоже переменного размера, но упрощенно возьмем, что он тоже 32 байта, а не ~100. Аналогично и дескрипторы записей можно принять по 32 байта. Тогда в этой же ситуации, в странице поместится лишь 12 записей. Результат катастрофический.

На практике, если в таблице объявить все поля, кроме первичного ключа, NULL и заполнять, в среднем, только четверть из них, но провал производительности, по сравнению PostgreSQL, будет в несколько раз.

Подобная ситуация и с VARCHAR. В DB2 он реализован откровенным костылем, когда в записи всегда присутствует два байта длины, опционально байт NULL признака, и фиксированная часть. Все, что не помещается в фиксированную часть, выносится в динамическую область переполнения, доступ к которой менее эффективен, чем к обычным страницам.

На фиксированной двухбайтовой длине уже часто проигрываем. В том же примере наименований контрагентов, лишь 0.15% имели длину свыше 127 байт.

А наличие фиксированной части приводит, либо, как минимум, к двукратной деградации производительности, если она короткая и всегда требует обращения к странице из области переполнения. Либо просто не дает никаких преимуществ в производительности, если фиксированная часть длинная.

Если честно, я в шоке. Столь существенного отставания DB2 от остальных СУБД на рынке я не ожидал.

Если идеология остального ПО на AS/400 до сих пор настолько подвержена легаси, с тех времен, когда время выполнения одной команды CPU было сравнимо со временем обращения к RAM, то с ней тоже все печально. И проблема совсем не в аппаратной части и, тем более, не в архитектуре CPU. Аппаратура лишь пытается хоть что-то сделать с тем легаси, с которым очень мало что можно сделать.

Что касается POWER10, то Вы, похоже, опять меня не правильно поняли. Это хороший CPU, вполне способный конкурировать с продукцией AMD и Intel. Может ARM и RISC-V скоро подтянутся. Но не более того. Никакого принципиального конкурентного преимущества у него нет. Смотрим на список суперкомпьютеров и видим там те же EPIC и Xeon, оказывающие ничуть ни хуже, а порой и лучше, чем CPU IBM.

PowerAXON хорошо, но использование канала доступа к RAM для межпроцессорного взаимодействия - ничем не хуже, с точки зрения производительности. Зато удешевляет и упрощает системы, имеющие до 4 сокетов/768 ядер, которые намного более востребованы на рынке, чем суперкомпьютеры/мейнфреймы.

Отделение компилятора от СУБД является определённым недостатком удобства и эффективности современных языков программирования, хотя увеличивает гибкость. Задумывалось изначально это всё не так, язык SQL разрабатывался в IBM фактически как подмножество PL/I.

Ну тут чуть сложнее... Есть система. В нее интегрированы СУБД, движок SQL, компиляторы. И все они между собой на системном уровне взаимодействуют.

Строго говоря, елси в RPG на используются SQL запросы, то оно копилируется как RPGLE. Если используются - как SQLRPGLE - разные команды для компиляции. Во втором случае сначала запускается SQL-препроцессор, а потом уже компилятор.

И обратно - на RPG можно писать хранимые процедуры, UDF/UDTF. Т.е. там все между собой очень тесно переплетено.

Реализация в языке, это еще и реализация в стандартной библиотеке и поддержка оптимизаций компилятором. Например, какое значение выдаст sqrt(x), если x -- типа real? В каком-нибудь C это будет real, а в нормальном языке это зависит от знака x :)

А если x имеет тип decimal? Который сам по себе не поддерживается языком и для него нужно предварительно создать объект нужного класса?

А вот тут уже нужен Lisp)

Лисп прекрасен, но в смысле производительности не тянет.

Я как-то сравнил программы, выполняющие одинаковую обработку списков на Лиспе и на Фортране. Программа на Лиспе заняла 4 строчки, а на Фортране примерно 400. Но на Фортране она работала раз в 20 быстрее, чем в скомпилированном Лиспе. А если списки в Фортране заменить на массивы, то получалось ещё на порядок быстрее.

А (declare (optimize speed)) пробовали добавить? Типы явно прописать? Лисп очень хорошо умеет в оптимизацию, но он слишком "внимателен" и не включает ее там, где она может сломать универсальность. В том же случае с sqrt, если явно ему не указать, что тип аргумента не отрицателен, то Лисп добавит проверку на отрицательный аргумент и будет учитывать, что возвращаемое значение может быть комплексным числом, а это, в свою очередь, заставит его все места, где оно используется, тоже снабдить проверками. Ну и на счет массивов -- можно сделать их объектами, генерировать и хранить с каждым массивом функцию для доступа к его элементу, которую компилировать "на ходу" в момент создания массива. Тогда ей не придется вытаскивать из памяти размеры массива, например, что сделает доступ примерно таким же быстрым, как в фортране, когда размер массива задан при компиляции, только тут размеры могут быть динамическими. Наконец, есть такая штука, как маросы компилятора в Лисп. Благодаря им, например, может существовать библиотека (!) добавляющая поддержку SIMD-инструкицй процессора в компилятор, который их не поддерживает.

Всё-таки Лисп в своей концепции довольно далёк от современного железа. Возможно, на IBM 704, где были знаменитые регистры CAR и CDR, тогдашний Лисп и более эффективно транслировался (хотя тогда, вроде, был только интерпретатор), но в современном железе всё заточено под векторно-конвейерные операции, и это совсем не то, что цепочки условных проходов по указателям в лисповских списках.

Другое дело, что Лисп обычно и применяют не там, где требуется высокая производительность любой ценой, а там, где нужно запрограммировать концептуально сложные, универсальные вещи.

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

Вообще, это две совершенно разные ветви развития, Фортнан шел по пути совершенствования компиляторов, оставляя архаичные формы в языке, за которые его так не любят. Зато по уровню оптимизации фортрановские компиляторы рвут всех и всё. Лисп же шел по пути совершенствования именно языка и шел этим путем 60+ лет. Его ниша -- сложные алгоритмы, то есть действительно сложные, которые не помещаются в голове программиста целиком. Все модные в разное время концепции программирования или появились сразу в Лиспе или были им приняты в первых рядах. Впрочем, это иногда выливается в вещи типа CLOS, который не очень похож на объектно-ориентированное программирование в других языках, зато более логичен и гибок. Забавно, что два самых старых языка до сих пор остаются лучшими в своих нишах.

Лисп, который умеет в самомодифицирующийся код и строгую типизацию, может быть не менее эффективен даже в фортрановской нише

Если только фортрановский кодогенератор написать на Лиспе руками. Что в принципе, конечно, возможно, так как всю науку, как говорится, можно свести к S-выражениям, но практически в арсенале программиста этого нет.

А в остальном я с Вами согласен.

Какая дичь в Эппле (ладно, в APL'е).
Да и вообще синтаксис более-менее приятный только в Фортране. Не даром он самый живой из перечисленных.
П.С. Да-да, дело вкуса. Знаю-знаю.

Ада, кмк это язык, опередивший время и ещё не достиг пика признания.

Странно что не упомянут православный "Си" 1972 (или раньше?) года издания и который по сию живее многих молодых трупиков. ;)

А как же величайший Pascal, и Фаронов, пророк его в 90х.

А что делает программа в примере на PL/I?

Описывает и вызывает какие-то многочисленные текстовые экранные формы. Очень похоже на какой-то автоматически генерируемый код или близкую по сути вещь.

Писал на всех из перечисленных, кроме ADA и APL. Ностальгия 😁

Видимо, Fortran претерпел очень сильные изменения, потому что приведенный код не похож ни на Fortran IV, ни на Fortran 77, на которых я начинал свою карьеру в 80-х.

И это нормально. Плюсы современные от первых Страуструпа отличаются не менее сильно.

Фортран 2000+ – фактически совершенно другой язык, чем IV и 77. И по фактически используемому синтаксису, и по своему позиционированию. Но он тянет совместимость со старыми конструкциями, что хорошо с точки зрения использования легаси, но очень тяжело для современного первоначального обучения.

Вспомнил годы за гринскрином AS/400 и RPG, объекты с ограничением длины имён в 10 символов, прослезился 🥲

Ну ограничение длины имен объектов в 10 символов может казаться непривычным, но ничего страшного тут нет на самом деле.

А вот сам RPG сильно ушел вперед за последние годы. Появились динамические массивы, причем, как с ручным управлением размером - dim(*var) (размер меняется при помощи %elem(arr) = ...), так и с автоматическим - dim(*auto) где размер изменяется автоматически при добавлении нового элемента, например arr(*next) = ....

Есть overload процедур для процедур, имеющих разный набор параметров но одинаковый тип возвращаемого значения

// Отправка сообщения в queLIFO/queFIFO очередь
// Возвращает количество отправленных байт
// в случае ошибки -1
dcl-pr USRQ_SendMsg int(10) overload(USRQ_Send: USRQ_SendKey);

dcl-pr USRQ_Send int(10) extproc(*CWIDEN : 'USRQ_Send') ;
  hQueue    int(10)                    value;                                  // handle объекта (возвращается USRQ_Connect)
  pBuffer   char(64000)                options(*varsize);                      // Буфер для отправки
  nBuffLen  int(10)                    value;                                  // Количество байт для отправки
  Error     char(37)                   options(*omit);                         // Ошибка
end-pr;

// Отправка сообщения в queKeyd очередь
// Возвращает количество отправленных байт
// в случае ошибки -1

dcl-pr USRQ_SendKey int(10) extproc(*CWIDEN : 'USRQ_SendKey') ;
  hQueue    int(10)                    value;                                  // handle объекта (возвращается USRQ_Connect)
  pBuffer   char(64000)                options(*varsize);                      // Буфер для отправки
  nBuffLen  int(10)                    value;                                  // Количество байт для отправки
  pKey      char(256)                  const;                                  // Значение ключа сообщения
  nKeyLen   int(10)                    value;                                  // Фактический размер ключа
  Error     char(37)                   options(*omit);                         // Ошибка
end-pr;

Везде используем USRQ_SendMsg, а компилятор уже по набору аргументов сам решает что вызвать - USRQ_Send или USRQ_SendKey

Появились разные %split, %concat, %concatarr, %list, конструкция for-each:

for-each FileKey in %list('ACF': 'ACJ': 'ACB': 'AC4': 'ACP');

или

For-Each Element In %split(NamForNormalize);

Ну и сама по себе платформа интересная и богатая возможностями, если копнуть поглубже.

Да, еще забыл - появилась очень удобная (концептуально) вещь - блок on-exit в процедурах куда выполнение кода приходит в любом случае - как после return (с возможностью замены возвращаемого функцией значения), так и в случае возникновения исключения (для определения сего можно определить специальный индикатор - логическая переменная в RPG - который будет установлен в *on в случае попадания в on-exit по исключению или *off при нормальном выходе.

Использование такого механизма позволяет определить единую точку выхода из процедуры в которой проводить все необходимые на выходе операции.

И после того как из-за пандемии выросло количество безработных, инфраструктура не выдержала возросшей нагрузки

Где-то мелькало, что не выдержала не система на Коболе, а вполне новомодный веб-интерфейс

Тут и мелькало

«С ума сходило веб-приложение между мейнфреймом и внешним миром. Именно оно падало», — рассказывает программистка и писательница Марианна Беллотти, годами работавшая с государственными системами и следившая за этой системой Нью-Джерси. Но, по словам историка Хикса, властям было слишком неудобно признать «ой, да, это сломались наши веб-системы».

Есть мнение, что проблема была не технической. Там количество транзакций это капля в море. Просто если выбросить на счёта граждан кучу кэша в один день, то это спровоцирует гипер-инфляцию - коммерсанты сразу взвинтят цены на эту дельту. А так размазали выплаты на несколько месяцев. Объяснить приоритезацию выплат техническими проблемами было гораздо проще, чем образовавшееся по факту неравенство.

Sign up to leave a comment.