...

суббота, 2 марта 2019 г.

Надежное программирование в разрезе языков. Часть 2 — Претенденты

Первая часть с функциональными требованиями тут

Заявленные как языки программирования с прицелом на надежность.

В алфавитном порядке — Active Oberon, Ada, BetterC, IEC 61131-3 ST, Safe-C.
Сразу дисклеймер (отмазка) — это никак не агитация “все на левый борт”, и обзор скорее академический — у языка может не быть не только активно поддерживаемой современной среды разработки, но и даже компилятора под Вашу платформу.

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

Как показатель наглядности языка, я выбрал реализацию известной многопоточной задачи Дейкстры об обедающих философах. Реализация есть в учебниках по языку и на форумах, что облегчило мне работу — осталось только адаптировать. Например недавняя хабра статья про современный С++ содержит реализацию на C++17 для сравнения.

Active Oberon (2004)


Создавался с оглядкой на опыт Паскаля, Модулы, предыдущих Оберонов с 1988г, Java, C#, Ады, а также практический опыт применения. Имеет реализацию в виде ОС A2
, которая может выступать рантаймом поверх *nix или Windows. Исходники А2 и компилятора по ссылке

Также есть проект Oberon2 to C Compiler (OOC) не привязанный к среде Оберон. Это немного другой диалект, отличия описаны ниже.

Ключевая фишка Оберона — исключительная краткость спецификации. Это 16 страниц по базовому Оберону-2 плюс 23 страницы по многопоточному Активному расширению.

Простой и понятный синтаксис, исключающий явные ошибки.
Идентификаторы регистрозависимые.
ООП с объектами на куче с автосборщиком мусора(GC).
Отличается от предшественников более привычным синтаксисом ООП в виде Экземпляр.Метод (раньше было Метод(Экземпляр)) и поддержкой многопоточности с примитивами синхронизации.
В реализации ООП нет динамической диспетчеризации, что легко может привести к ситуации — забыли дописать обработку для нового типа.
Потокам можно назначить приоритет и высоким/риалтайм они не прерываются GC.
Строки в виде массивов UTF-8.
Рантайм (Система Оберон) дает интересные возможности для перезапуска сбойной процедуры/модуля/потока в случае рантайм ошибки — адресации памяти или, например, целочисленного переполнения.

Недостатком можно счесть отсутствие RAII, и удобной обработки ошибок — все через коды возврата, за исключением варианта ниже.

Оберон-2 OOC


Удобнее для экспериментов, поскольку не требует ОС Оберон — компилируется в ANSI С и нет проблем интероперабельности. Отличия от Активной версии — нет встроенной в язык многопоточности — вместо этого есть модуль работы с PThreads, зато есть UTF16, иерархическая модульность и системный модуль для работы с исключениями.

Модула-3


Есть еще родственник из немного другой ветки развития в виде Модулы-3. Создавалась на базе Оберона в противовес переусложенной Аде. Реализация тут

По сравнению с Активным Обероном добавлены дженерики и исключения, есть библиотеки для практической работы с Юникодом, GUI, и даже Постгрессом. Упрощена интеграция с С. Другая семантика многопоточности. RAII в виде WITH (похоже на using в C#).
Но похоже, что развитие Модулы-3 остановилось в 2010 году.

Дисклеймер. Запустив WinAOS я столкнулся с TRAPами (aka abort/stacktrace или runtime error) на ровном месте — даже диспетчер задач работает с ошибками, и хотя система/рантайм и не вылетали — а только приложение, меня посетило определенное сомнение о том, что надежность определяется языком программирования =(
Также AOC является в достаточной степени замкнутой на себя, со своим подходом к разработке.

Исходник Обедающих Философов
MODULE Philo;
(* Dining Philosophers Example from Active Oberon Language Report by Patrik Reali *)
(* Adapted for running in AOS by Siemargl *)


IMPORT Semaphores :=  Example8, Out;

CONST
        NofPhilo = 5; (* number of philosophers *)
        
VAR
        fork: ARRAY NofPhilo OF Semaphores.Semaphore;
        i: LONGINT;
        
TYPE
        Philosopher = OBJECT
                VAR
                        first, second: LONGINT;
                        (* forks used by this philosopher *)

                PROCEDURE & Init(id: LONGINT);
                BEGIN
                        IF id # NofPhilo-1 THEN
                                first := id; second := (id+1)
                        ELSE
                                first := 0; second := NofPhilo-1
                        END
                END Init;
                
                PROCEDURE Think;  (* Need lock console output *)
                BEGIN {EXCLUSIVE}
                        Out.Int(first); Out.String(".... Think....");   Out.Ln;
                END Think;

                PROCEDURE Eat;
                BEGIN {EXCLUSIVE}
                        Out.Int(first); Out.String(".... Eat....");     Out.Ln;
                END Eat;

                
        BEGIN {ACTIVE}
                LOOP
                        Think;
                        fork[first].P; fork[second].P;
                        
                        Eat;
                        fork[first].V; fork[second].V
                END
        END Philosopher;
        
VAR
        philo: ARRAY NofPhilo OF Philosopher;
        
BEGIN
        FOR i := 0 TO NofPhilo DO
                NEW(fork[i], INTEGER(i));
                NEW(philo[i], i);
        END;
END Philo.

Philo.Philo1 ~

Ada (1980, последний действующий стандарт 2016)


Собственно, на первый взгляд тут есть все, что мне хотелось бы.
И даже чуть больше — есть числа с точным вычислениями с плавающей точкой. Например, есть риалтайм планировщик потоков, межпоточный обмен и формально верифицируемое подмножество языка SPARK. И еще много много всего.
Думаю, если бы для надежности Ады был нужен еще черт рогатый, он бы прилагался вместе с инструкцией по вызову в трудной ситуации =)
Реализация — ГНУтая Ада, развивается, стандартизована ISO/IEC.

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

Ada Reference Manual 2012 содержит 950 страниц.
Недостаток Ады кроме сложности — чрезмерная многословность, что впрочем было задумано в угоду читаемости. Из-за специфичности языковой модели безопасности, интеграция с “чужими” библиотеками затруднена.

На сайде Ada-ru есть хорошая обзорная переводная статья — первая ссылка.

Исходник Обедающих Философов
-- Code from https://rosettacode.org/wiki/Dining_philosophers#Ordered_mutexes
-- ADA95 compatible so can run in ideone.com

with Ada.Numerics.Float_Random;  use Ada.Numerics.Float_Random;
with Ada.Text_IO;                use Ada.Text_IO;
 
procedure Test_Dining_Philosophers is
   type Philosopher is (Aristotle, Kant, Spinoza, Marx, Russel);
   protected type Fork is
      entry Grab;
      procedure Put_Down;
   private
      Seized : Boolean := False;
   end Fork;
   protected body Fork is
      entry Grab when not Seized is
      begin
         Seized := True;
      end Grab;
      procedure Put_Down is
      begin
         Seized := False;
      end Put_Down;
   end Fork;
 
   Life_Span : constant := 20;    -- In his life a philosopher eats 20 times
 
   task type Person (ID : Philosopher; First, Second : not null access Fork);
   task body Person is
      Dice : Generator;
   begin
      Reset (Dice);
      for Life_Cycle in 1..Life_Span loop
         Put_Line (Philosopher'Image (ID) & " is thinking");
         delay Duration (Random (Dice) * 0.100);
         Put_Line (Philosopher'Image (ID) & " is hungry");
         First.Grab;
         Second.Grab;
         Put_Line (Philosopher'Image (ID) & " is eating");
         delay Duration (Random (Dice) * 0.100);
         Second.Put_Down;
         First.Put_Down;
      end loop;
      Put_Line (Philosopher'Image (ID) & " is leaving");
   end Person;
 
   Forks : array (1..5) of aliased Fork; -- Forks for hungry philosophers
                                         -- Start philosophers
   Ph_1 : Person (Aristotle, Forks (1)'Access, Forks (2)'Access);
   Ph_2 : Person (Kant,      Forks (2)'Access, Forks (3)'Access);
   Ph_3 : Person (Spinoza,   Forks (3)'Access, Forks (4)'Access);
   Ph_4 : Person (Marx,      Forks (4)'Access, Forks (5)'Access);
   Ph_5 : Person (Russel,    Forks (1)'Access, Forks (5)'Access);
begin
   null; -- Nothing to do in the main task, just sit and behold
end Test_Dining_Philosophers;


BetterC (dlang subset 2017, оригинальный D — 2001, D 2.0 — 2007)


Самая современная реализация из рассматриваемых. Полное описание языка довольно длинное — 649 страниц — см.оригинальный сайт.
Собственно это язык D, но с ограничениями ключом -betterC. Почему так ?!
Потому что стандартная библиотека D — Phobos, разрабатывается Александреску и получилась весьма хитромудрой, полностью построенной на шаблонах. Ключевое для данной темы, что Фобос неконтролируем в плане расхода памяти.

Самое важное что теряется в режиме BetterC — многопоточность, GC, строки, классы (структуры остаются — они близки по функционалу — только на стеке) и исключения (RAII и try-finally остаются).
Возможно, впрочем, часть программы писать на полном D, а критичную часть — на D -BetterC. Также есть системные атрибута функция для контроля неиспользования опасных эффектов: pure safe @nogc.
Обоснование режима от создателя языка.
А тут выжимка — что обрезано, а что осталось доступным.

Строки содержатся в Фобосе — и попытки их использовать в BetterC выливаются в адские ошибки инстантациации шаблонов на элементарных операциях вроде вывода строки на консоль или конкатенации. А в полном режиме D строки в куче и иммутабельные, потому операции с ними приводят к замусориванию памяти.

Мне приходилось несколько раз встречать жалобы на баги в компиляторе. Что впрочем неудивительно для языка, конкурирующего по сложности с С++. При подготовке статьи тоже пришлось столкнуться с 4мя ошибками — две возникли при попытке собрать dlangide новым компилятором и парой при портировании задачи о философах (например вылет при использовании beginthreadex).

Режим еще только недавно появился и ошибки, вызванные ограничением режима BetterC вылезают уже на этапе линковки. Узнать об этом заранее, какие фичи языка урезаны точно — приходится часто на собственном опыте.

Исходник Обедающих Философов
// compile dmd -betterC 

import core.sys.windows.windows;
import core.stdc.stdio;
import core.stdc.stdlib : rand;
//import std.typecons; // -impossible (
//import std.string;  - impossible



extern (Windows) alias btex_fptr = void function(void*) /*nothrow*/;
//extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow;
/* Dining Philosophers example for a habr.com 
*  by Siemargl, 2019
*  BetterC variant. Compile >dmd -betterC Philo_BetterC.d
*/

extern (C) uintptr_t _beginthread(btex_fptr, uint stack_size, void *arglist) nothrow;

alias HANDLE    uintptr_t;
alias HANDLE    Fork;

const philocount = 5;
const cycles = 20;

HANDLE[philocount]  forks;


struct Philosopher
{
    const(char)* name;
    Fork left, right;
    HANDLE lifethread; 
}
Philosopher[philocount]  philos;


extern (Windows) 
void PhilosopherLifeCycle(void* data) nothrow
{
    Philosopher* philo = cast(Philosopher*)data;

    
    for (int age = 0; age++ < cycles;)
    {
        printf("%s is thinking\n", philo.name);
        Sleep(rand() % 100);
        printf("%s is hungry\n", philo.name);

        WaitForSingleObject(philo.left, INFINITE);
        WaitForSingleObject(philo.right, INFINITE);

        printf("%s is eating\n", philo.name);
        Sleep(rand() % 100);
        ReleaseMutex(philo.right);
        ReleaseMutex(philo.left);
    }

    printf("%s is leaving\n", philo.name);
}

extern (C) int main() 
{
    version(Windows){} else { static assert(false, "OS not supported"); }

    philos[0] = Philosopher ("Aristotlet".ptr, forks[0], forks[1], null);
    philos[1] = Philosopher ("Kant".ptr, forks[1], forks[2], null);
    philos[2] = Philosopher ("Spinoza".ptr, forks[2], forks[3], null);
    philos[3] = Philosopher ("Marx".ptr, forks[3], forks[4], null);
    philos[4] = Philosopher ("Russel".ptr, forks[0], forks[4], null);

    foreach(ref f; forks)
    {
        f = CreateMutex(null, false, null);
        assert(f);  
    }

    foreach(ref ph; philos)
    {
        ph.lifethread = _beginthread(&PhilosopherLifeCycle, 0, &ph);
        assert(ph.lifethread);  
    }

    foreach(ref ph; philos)
        WaitForSingleObject(ph.lifethread, INFINITE);

    // Close thread and mutex handles
    for( auto i = 0; i < philocount; i++ )
    {
        CloseHandle(philos[i].lifethread);
        CloseHandle(forks[i]);
    }
    
    
        return 0;
}



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

IEC 61131-3 ST (1993, последний стандарт 2013)


Нишевой язык программирования микроконтроллеров. Стандарт подразумевает 5 вариантов программирования, но писать прикладное приложение к примеру в релейной логике это еще то приключение. Потому сконцентрируемся на одном варианте — структурированный текст.
Текст стандарта ГОСТ Р МЭК 61131-3-2016 — 230 страниц.
Есть реализации для PC/x86 и ARM — и коммерческие, самая известная из которых — это CODESYS (часто еще и сублицензированная с разными именами) и открытые — Beremiz — с трансляцией через С.

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

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

Исходник (не проверялся)
(* Dining Philosophers example for a habr.com 
*  by Siemargl, 2019
*  ISO61131 ST language variant. Must be specialized 4 ur PLC 
* )
CONFIGURATION PLC_1

VAR_GLOBAL
        Forks : USINT;
        Philo_1: Philosopher;  (* Instance block - static vars *)
        Philo_2: Philosopher;
        Philo_3: Philosopher;
        Philo_4: Philosopher;
        Philo_5: Philosopher;
END_VAR

RESOURCE Station_1 ON CPU_1
        TASK Task_1 (INTERVAL := T#100MS, PRIORITY := 1);
        TASK Task_2 (INTERVAL := T#100MS, PRIORITY := 1);
        TASK Task_3 (INTERVAL := T#100MS, PRIORITY := 1);
        TASK Task_4 (INTERVAL := T#100MS, PRIORITY := 1);
        TASK Task_5 (INTERVAL := T#100MS, PRIORITY := 1);

        PROGRAM Life_1 WITH Task_1: 
                Philo_1(Name := 'Kant', 0, 1, Forks);
        PROGRAM Life2 WITH Task_2: 
                Philo_2(Name := 'Aristotel', 1, 2, Forks);
        PROGRAM Life3 WITH Task_3: 
                Philo_3(Name := 'Spinoza', 2, 3, Forks);
        PROGRAM Life4 WITH Task_4: 
                Philo_4(Name := 'Marx', 3, 4, Forks);
        PROGRAM Life5 WITH Task_5: 
                Philo_5(Name := 'Russel', 4, 0, Forks);

END_RESOURCE

END_CONFIGURATION

FUNCTION_BLOCK Philosopher;
USING SysCpuHandling.library;
VAR_INPUT
        Name: STRING;
        Left: UINT; 
        Right: UINT;
END_VAR
VAR_IN_OUT
        Forks: USINT;
END_VAR
VAR
        Thinking:       BOOL := TRUE;  (* States *)
        Hungry: BOOL;
        Eating: BOOL;
        
        HaveLeftFork:   BOOL;
        TmThink:        TON;
        TmEating:       TON;
END_VAR
        TmThink(In := Thinking; PT := T#3s);
        TmEating(In := Eating; PT := T#5s);
        IF Thinking THEN  (* Just waiting Timer *)
                Thinking := NOT TmThink.Q;
                Hungry := TmThink.Q;
        ELSIF Hungry (* Try Atomic Lock Forks *)
                IF HaveLeftFork 
                        IF SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Right, bSet := 1) = ERR_OK THEN
                                Hungry := FALSE;
                                Eating := TRUE;
                        ELSE
                                RETURN;
                        END_IF
                ELSIF
                        IF SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Left, bSet := 1) = ERR_OK THEN
                                HaveLeftFork := TRUE; 
                        ELSE
                                RETURN;
                        END_IF
                END_IF
        ELSIF Eating  (* Waiting Timer, then lay forks *)
                IF TmEating.Q THEN
                        Thinking := TRUE;
                        Eating := FALSE;
                        HaveLeftFork := FALSE;
                        SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Right, bSet := 0);
                        SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Left, bSet := 0);
                END_IF
        END_IF
END_FUNCTION_BLOCK


Safe-C (2011)


Экспериментальный С с удалением опасных фишек и с добавлением модульности и многопоточности. Сайт проекта
Описание примерно 103 страницы. Если выделить отличия от С — совсем мало, около 10.

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

В стандартной библиотеке есть минимальный набор функций для GUI, многопоточности, сетевых функций (в т.ч http-сервер).

Но — данная реализация только для Windows x86. Хотя код компилятора и библиотеки открыт.

В рамках другой исследовательской задачи я собрал макет Веб-сервер, собирающий данные с IoT датчиков: 75 Кб исполнительный модуль, и < 1Мб частичный набор памяти.

Исходник Обедающих Философов
/* Dining Philosophers example for a habr.com 
*  by Siemargl, 2019
*  Safe-C variant. Compile >mk.exe philosafec.c
*/

from std use console, thread, random;

enum philos (ushort) { Aristotle, Kant, Spinoza, Marx, Russell, };
const int cycles = 10;
const ushort NUM = 5;
uint  lived = NUM;


packed struct philosopher // 32-bit
{
        philos  name;
        byte left, right;
}

philosopher philo_body[NUM];

SHARED_OBJECT forks[NUM];

void philosopher_life(philosopher philo) 
{
        int age;
    for (age = 0; age++ < cycles; )
    {
        printf("%s is thinking\n", philo.name'string);
        delay((uint)rnd(1, 100));
        printf("%s is hungry\n", philo.name'string);

                enter_shared_object(ref forks[philo.left]);
                enter_shared_object(ref forks[philo.right]);

        printf("%s is eating\n", philo.name'string);
        delay((uint)rnd(1, 100));

                leave_shared_object(ref forks[philo.right]);
                leave_shared_object(ref forks[philo.left]);
    }

    printf("%s is leaving\n", philo.name'string);
    InterlockedExchange(ref lived, lived-1);
}


void main()
{
        philos i;

        assert philosopher'size == 4;
        philo_body[0] = {Aristotle, 0, 1};
        philo_body[1] = {Kant, 1, 2};
        philo_body[2] = {Spinoza, 2, 3};
        philo_body[3] = {Marx, 3, 4};
        philo_body[4] = {Russell, 0, 4};
        
        for (i = philos'first; i <= philos'last; i++)
        {
                assert run philosopher_life(philo_body[(uint)i]) == 0;
        }

        while (lived > 0) sleep 0; // until all dies

        for (i = philos'first; i <= philos'last; i++)
        {
                destroy_shared_object(ref forks[(uint)i]);
        }
}


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

Исходники из статьи на гитхабе

Let's block ads! (Why?)

[Из песочницы] Lazy loading of Feature Module from the «node_modules» folder

If someone of you has tried create angular libraries, he may face the issue with lazy loading Feature Module from node_modules. Let's dive deeper and go thru the dark water.

image![image](http://about-telegram.ru/wp-content/uploads/2018/03/svobodnyj-ot-zabot-lenivec-stickers-telegram_12.jpg)

If you are not familiar with question "How to create the library?" — There are at least two tools for creating angular library:


  1. Angular CLI (ng-packagr under the hood);
  2. Directly the ng-packagr;

You able to get more details by clicking on the links above, all other let's move further.


Lazy Modules (Feature Modules)

image
So, If you have already worked with Angular you have to know about Angular modules and for what purposes you need them.

A module usually has to keep a bunch of components, services of directives which represent a certain self-sufficient piece of functionality. Often developer creates a separate module for a feature which has not to be loaded to app until a user will not go to particular page.

And now the time for Feature Store (not about this for now) and Feature module.

If you include Lazy Loaded modules into some parent module they wouldn't be lazy, because you will declare them into the app and in time of compilation TypeScript into the JavaScript Webpack will add the code of those modules into the main bunch and application will load all that code on startup.

Only one correct way to declare a lazy module in routing.

const routes: Routes = [
  {
    path: 'reports',
    loadChildren: './reports/reports.module#ReportsModule'
  }
];

So you provide the special string which actually "#" and the app will know that this module has to be loaded separately from the main app.

Troubles Begin

image
All goes fine if Feature Module is a part of source code of your app, but what if this is a compiled library set up using the npm? — It does not work in a usual way.

The main problem that when you try to register such Feature Module by usual string you will facing the error.

const routes: Routes = [
  {
    path: 'reports',
    // will not work
    loadChildren: 'my-lib#ReportsModule'
  }
];

It causes due to such kind of declaration are not compatible for compiled modules.

You able to make a wrapper and then declare it in routs.

import { ReportsModule } from "my-lib";
@NgModule({
  imports: [ReportModule],
  exports: [ReportModule]
})
export class ReportsWrapperModule { }

const routes: Routes = [
  {
    path: 'reports',
    loadChildren: './wrapper.module#ReportsWrapperModule'
  }
];

BUT, who interested in creating 15 wrappers for 15 modules? — I'm not!


Possible solutions

image

I won’t hide I didn't waste time analyzing why this happens due to Webpack or some Angular CLI. I found two possible solutions.


Solution #1. Library compiled and Feature Module has no nested feature modules

Link for the working example.

First step define what type of LoadChildren attribute

type LoadChildren = string | LoadChildrenCallback;

type LoadChildrenCallback = () => Type<any> | NgModuleFactory<any> | Promise<Type<any>> | Observable<Type<any>>;

Interesting! So, theoretically, it's possible to use import() to return promise with the required module.
Next code has to be fine.

const routes: Routes = [
  {
    path: 'reports',
    loadChildren: () => import('my-lib').then((res) => res.ReportsModule)
  }
];

Oh, what happens? — We see errors in the console… Yep, just change tsconfig.json

{
  ..
  "module": "esNext",
  ..
}

Now it has to work fine.


Solution #2. Feature Module have nested feature modules (done only for a non-compiled library)

Link for the working example.


  1. You have not to compile the library before packaging to npm package;


  2. As the source of library is not compiled you have to include it into compilation process of your app. Just change tsconfig.app.json;

    "exclude": [
      "test.ts",
      "**/*.spec.ts",
      "../node_modules/**/*.spec.ts",
      "../node_modules/**/test.ts"
    ],
    "include": [
      "*.ts",
      "./environments",
      "./app",
      "../node_modules/my-lib"
    ]
    

  3. Good news — no need to use import();

    const routes: Routes = [{
    path: "reports",
    loadChildren: "my-lib#ReportsModule"
    }];
    

    Tadam!


P.S. These solutions tested with Angular 7 only.

Thanks for attention, enjoy.

Let's block ads! (Why?)

В чем особенности и задачи звукового сопровождения игр

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


Фото George Becker / PD

Немного истории


Цифровой звук как таковой появился достаточно поздно. Поэтому первая полноценная компьютерная игра — Spacewar! 1962 года выпуска — была немой. Геймплей сопровождал лишь шум от сопоставимого по размерам с холодильником «миникомпьютера» PDP-1.

Первой коммерческой игрой со звуком стала Computer Space — аркадная версия Spacewar!, появившаяся в 1971 году. Миникомпьютеры того времени были дорогими, а бюджет проекта был мизерным — поэтому железо для аркады было создано с нуля.

Один из создателей игры, Тэд Дэбни (Ted Dabney), имея опыт работы над аудиооборудованием в компании Ampex, смог встроить в устройство простой по современным меркам генератор аудио. Благодаря нему в игре звучат выстрелы, взрывы и шум ракетных двигателей.

Годом позже создатели Computer Space, уже под именем Atari выпустили легендарный игровой автомат Pong!. Он и сделал звук стал неотъемлемой частью игр.

Роль звукового чипа в нём выполняла микросхема для синхронизации видеосигнала. Такие чипы обычно оперируют на очень высоких частотах (приблизительно 4,4 МГц в системах формата PAL и 3,6 МГц в системах формата NTSC). Если эту частоту понизить, генерируемый сигнал можно услышать. Это и сделали создатели игры.

С ростом популярности домашних консолей гонка за лучший звук перекочевала в гостиную. Atari 2600 77 года выпуска могла похвастаться двухканальным аудиочипом. В 1983 году пользователям консолей Intellivision стал доступен внешний модуль для голосового синтеза. Затем этот функционал встроили в основную систему, на что Atari ответили выпуском модели 5200 с 4-канальным чипом POKEY.

Чуть позже в гонку вступили микрокомпьютеры. В то время как Commodore PET, Apple II и ранние IBM PC поставлялись с простыми пьезоизлучателями, Commodore 64 содержал в себе микросхему с трехголосным цифровым синтезатором. Чип SID, сделавший подобный функционал возможным, был любим публикой и выпускался в продуктах компании до 1989 года. Тембр каждого из трёх его голосов можно было «на ходу» менять, создавая иллюзию более сложной полифонии. Благодаря этому прорыву появились первые игровые композиторы.

В 1987 году рынок звуковых устройств для домашних компьютеров по-настоящему взорвался. IBM выпустили Music Feature Card, с звуковым чипом из флагманского синтезатора Yamaha DX-21. Эта карта стоила почти $500 (более тысячи современных долларов) и нацеливалась на профессиональных музыкантов. Популярной бюджетной опцией был Covox Speech Thing — 8-битный DAC, продававшийся за $80. А в среднем ценовом сегменте Creative соревновалась с продуктами AdLib.


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

В 90-е Creative поняли, что будущее — за цифровой звукозаписью и захватили львиную долю индустрии, сделав на этом акцент. Sound Blaster 16 и последующие модели линейки принесли PCM-аудио CD-качества в мир домашних ПК.

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

Звук как источник информации


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

В хоррорах и шутерах четко слышны шаги противников, что позволяет понять, где они находится. В Battlefield по звуку можно определить, наведены ли на игрока ракеты. В Legend Of Zelda для NES стены, которые можно пробить, издают характерный звук при ударе мечом. В более современных играх серии существует целый диапазон драматических звуков. Некоторые и вовсе существуют исключительно в информативных целях. Например, монетки в играх Марио звенят, когда их подбираешь.

Разработчики Hellblade: Senua's Sacrifice инновативно подошли к созданию информационных звуков. Персонаж, которым управляют игроки, слышит голоса в голове. Именно они помогают героине в битве, предупреждая, с какой стороны находится противник и когда стоит атаковать. Такая озвучка погружает игрока в шизофрению героини максимально глубоко, при этом предоставляя важную игровую информацию.


Фото kanonn / CC BY-ND

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

Музыка и атмосфера


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

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

В игре No Man's Sky процедурно-генерируемый саундтрек от британской пост-рок группы 65daysofstatic показывает бесконечность вселенной. У каждой планеты, каждой галактики своя мелодия, собранная из разных кусочков специальным алгоритмом, и непохожая на остальные.

Объёмный звук


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

Бинауральное аудио используется в вышеупомянутой игре Hellblade: Senua’s Sacrifice, а также в новинке Metro: Exodus. При такой записи микрофоны устанавливаются в уши маникена, и считывают звук для правого и левого уха отдельно. Объемность результата моментально ощущается, без необходимости использовать многоканальное оборудование.

Многоканальное аудио встречается в играх чаще, но требует специального оборудования, которое многие не решаются покупать. Среди знаменитых игр, использующих 7-канальное аудио — обе части легендарного хоррора «Амнезия», командная игра Rocket League и новый DOOM.

Игровой звук за пределами игровой культуры


Даже далекие от видеоигр люди узнают джингл прохождения уровня в Super Mario, звон колечек в Sonic The Hedgehog и удар шарика в Pong!.. Некоторые саундтреки и игровые композиторы достигли признания за пределами игрового мира. Акира Ямаока, автор музыки к играм серии Silent Hill, исполняет свои произведения в концертных залах и филармониях.

Одновременно с этим в игровой мир проникли более «традиционные» композиторы, подчеркивая важную роль видео игр в современной культуре. Например, немецкий композитор Ханс Циммер написал саундтрек к одной из частей Call Of Duty.

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



Дополнительное чтение в нашем «Мире Hi-Fi»:

Олдскул: на чём выходили игры — обсуждаем необычные носители
Как звуки и музыка делают видеоигры «живыми»
Какой он: российский рынок стриминговых сервисов
Восемь аудиотехнологий, которые попадут в зал славы TECnology в 2019 году
Как превратить компьютер в радио, и другие способы извлечь музыку из выч. систем


Let's block ads! (Why?)

[Из песочницы] Мошенники в розничных сетях

Привет, Хабр!

Я работал продавцом-консультантом несколько лет в одной крупной розничной сети.


За это время я узнал и научился немалому количеству методов заработка на покупателях, увидел мошенничество со стороны самой Компании, её руководства и подчиненных. Думаете, обманули вас или нет? Тогда прошу под кат.
Не хочу тыкать пальцами, условно назову такую сеть «VAIO».

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

Дело было в декабре 2018.

Компания вводит новую акцию для клиентов: «В период с 15 по 20 декабря с каждой покупки клиенту возвращается 20% на его бонусную карту лояльности в виде Кэшбека. Бонусами можно оплатить до 50% товара. Период действия бонусов — до 01.02.2019»

Суть мошенничества: клиент делает покупку, мы пробиваем это всё на свою карту и получаем 20% от стоимости покупки. Так как наши дисконты создаются по номеру телефона, то и СИМ-карт было куплено сотрудниками нашего магазина немало.

Как результат спустя пару недель у моих коллег уже было обилие техники Apple и Samsung на руках!

Как раз таки в этот момент к моим коллегам пришла гениальная идея. «А почему бы не просмотреть и не найти жирные продажи с других магазинов?» — подумал я, и быстро поделился идеей с зам. директора.

База 1С на наших компьютерах не позволяла нам видеть отчеты. по продажам других магазинов, и изменять номера дисконтов тоже. Тогда, включив небольшие знания «айтишника», была создана небольшая программа по перехвату паролей, уверен вы все такие делали. Переслать её менеджеру с правами администратора по почте не составило труда.

А дальше дело за малым:

  • находим столичный ТЦ, самый прибыльный магазин сети;
  • находим крупную продажу, с нее дисконт;
  • меняем номер на тот, который нам нужен;
  • ловим продажу за наличку на сумму бонусов, так как оплатить можно только 50% и проводим все позиции одним чеком;
  • зовем кого-нибудь для совершения покупки.

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

Но радость от новой покупки длилась не долго — реальные покупатели пришли за своими бонусами в магазин, и… их там уже не было! Представляю их удивление.

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

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

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

До этого, два или три года были схемы попроще.

1. «Мажорный зазор» — приходят богатые «постоянники», которые часто у нас покупают и нам доверяют. Выбираем товар, естественно они согласны автоматом и на платные услуги и на настройки и на всё что нам выгодно. На кассе оставляют сумму озвученной налички и уходят. Естественно чеки их не интересуют.

2. «Пустой чек» — как вы понимаете, в любой сети есть планы продаж и продавать «голый» товар продавцу катастрофически не хочется. Если клиент не особо глупый и на платные настройки не соглашается, делалась ручная скидка на товар, в зазор вбивались нужные позиции услуг, клиенту говорилось что пойдет в подарок. Если не было скрытых скидок либо промо-цен на товар, звонили категорийному менеджеру и просили скидку за наличку якобы постоянникам магазина.

3. «рассрочка 0%» — ну здесь мне кажется все понятно… ) Обычно при любой продаже в кредит услуги и всякого рода «антивирусы» добавлялись по стандарту! С этого продавец зарабатывал в разы больше чем с основного товара. В 50% людям достаточно было озвучить суму ежемесячного платежа, даже не спрашиваю сумму всей покупки. Если же люди настойчивые и не глупые, молча добиваем 2-4 шт. антивирусов Dr. Web. В чем преимущество кредитов? Можно запросто не отдавать фискальный чек. Печатаем пакет документов, выделяем маркером реквизиты для оплаты и человек доволен. Делаем фото договора и по кассе проводим, когда клиент уже ушел. Работает в 98% случаев!!! Бывали случаи, когда сумма новенького смартфона была 25000 грн, и рассрочка на 12 месяцев превращала общую сумму в 34000 грн, о которой даже не подозревают по сей день.

Кстати, люди покупавшие в сети «VAIO», проверьте ваши чеки!

Пример чека

Нет ли там часом пункта — «Технічна підтримка 365»? Это самый дорогой для покупателя, и абсолютно не нужный. Это комиссия банку за пользование кредитов на большой период, но при этом с нее продавец зарабатывает 10% от стоимости. Как вы понимаете, у нас была возможность добавить комиссию без заработка, и вы бы заплатили меньше… но никто так не делал.

4. «Подарок» — ну как уже думаю догадались, большинство товаров, которые шли по акции в подарок к более дорогому, оставались у продавца а затем продавались здесь же в магазине. Думаю, объяснять больше не нужно.

5. «Замена Б/У-шкой» — было и такое! (Клиент берет за наличку условный iPhone X за 30к грн, наличка откладывается под кассой, люди уходят довольные. На авито или ОЛХ покупался такой же телефон но в Б/У состоянии за 20-24к и ложился на место как будто там и был.
Стоит ли упоминать, что потом такой товар уезжал дальше на склад и в конечном итоге продавался обычным людям?.. Или что все эти способы до сих пор применяются ?!

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

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

Не попадайтесь на обман консультантов!

Let's block ads! (Why?)

История советских кассетников: эволюция “Десны”, MK-60 made in USA и народные магнитофоны 70-х

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

Мне было интересно проанализировать насколько наши разработчики приблизились к коллегам из Японии, Западной Европы и США, удалось ли им догнать и перегнать, а также понять, почему советские разработки в этой области порой пользовались редким или т. н.”вынужденным” спросом, а большинство их современников стремились приобрести зарубежные образцы.

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

Spirit of 1969 или 26 мм оригинальной конструкции


История советских кассетных магнитофонов под стандарт компакт-кассета начиналась на 5-6 лет позже, чем на западе, что в целом совпадает с хронологическим отставанием Страны победившего развитого социализма от “западных партнёров” по электронике широкого потребления. Известно, что первые кассетные магнитофоны (с магнитной проволокой) появились еще в Третьем Рейхе в 1930-х, такие, в частности, выпускались компанией C. Lorenz AG. Первый кассетный магнитофон с магнитной лентой был выпущен в 1950-м году, им стал Loewe Optaphon.

Кассетный магнитофон 30-х

Loewe Optaphon

Всё это время кассетам не придавали значения в СССР и обходились катушками, которые получили народное наименование бобины. В 1963-м компания Philips представила компакт-кассету, а в 1964 появилось одно из первых портативных устройств для его воспроизведения, им стал Philips EL3300. В дальнейшем именно этот портативный кассетный магнитофон послужил прообразом для советского первенца “Десна”.


EL3300


«Десна»

Следует отметить, что в 1960-х в Стране советов магнитофоны были в большом дефиците, и до появления “Десны” существовали только бобинники. Понимая отставание в этой области, советские чиновники поставили инженерам задачу скопировать Philips EL3300. Разработку (т.е. копирование механики и адаптацию электроники) поручили харьковскому радиозаводу «Протон», который к 1969 году сумел освоить серийный выпуск новинки.

Компоновочная схема, конструкция лентопротяжного механизма, а также дизайн корпуса был идентичен EL3300. Электроника имела ряд существенных отличий и местами даже превосходила американскую разработку. Так усилитель советского устройства имел четыре каскада (у Philips было три), для двигателя был предусмотрен отдельный транзисторный стабилизатор частоты вращения. Отличалась и элементная база, так американское устройство использовало семь, а “Десна” девять германиевых транзисторов. Значимым отличием стало напряжение питания (9 В для “Десны, 7,5 у EL3300), для чего в “Десне” понадобилось увеличить количество батарей питания. Это привело к росту габаритов — длина выросла на 26 мм.


EL3300 внутри

Характерных достоинств, кроме относительно небольшого размера, по сравнению с катушечными собратьями, у магнитофона не было, и был по крайней мере один вопиющий недостаток — цена. Стоил гаджет 220 рублей — около 2-х зарплат опытного инженера. Учитывая низкий 4-й класс устройства, можно считать, что новинка была неконкурентоспособна даже на изголодавшемся по технике советском рынке.

Торопливые «Протоны»


Отдельной проблемой было достать кассеты, которые в то время выпускались совсем небольшими тиражами и были редкостью. Что интересно, компакт-кассеты “Протон МК-60” (с длительностью 38, 40 или 60 минут) создали раньше, чем появилась “Десна”.

Сам магнитофон планировали выпустить к 50-летию Великой Октябрьской социалистической революции, т.е. в 1967-м году, но не успели, а первый тираж “Протона” уже появился на свет. Скопировать носитель оказалось проще, чем адаптировать для серии забугорный магнитофон.

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

Более того, до начала 70-х кассеты не были полностью советскими, ленту для них выпускали в ГДР на предприятии «Filmfabrik Wolfen». С 1971-го года выпуск пленки для кассет организован на нескольких предприятиях СССР, в частности, на заводе “Свема”. Позже, там же начали производство кассет.

Ценник, как и в случае с первым кассетным магнитофоном, для советского человека в конце 60-х был почти космическим — по 6 рублей за одну кассету. Это, как и дефицитность носителя, также не способствовало популярности устройства.

По сей день живет легенда (https://ift.tt/2H9Mas1) о том, что на первых “Протон МК-60” можно было обнаружить различного вида незатертые надписи “Made in USA”, а также, что они окончательно пропали в начале 70-х. Мне не удалось найти подтверждения этому, но вполне допускаю, что такое могло быть.

Буду рад комментариям, поделитесь своими мыслями по поводу того, как надпись могла оказаться на кассете (у меня есть несколько гипотез).

Потомки “Десны”


Несмотря на сравнительную неудачу первого кассетника, Харьковские инженеры высоко оценили модернизационный потенциал своего детища. Забегая вперед, скажу, что советский “филипс” модернизировали аж до 1982-го года. Проведя основательную работу над ошибками, к 1971-му году выпустили «Спутник» и «Спутник-401». Через год производство модернизированной версии освоил приборостроительный завод в Арзамасе. Очередной доработанный клон “Десны” получил звучное название «Легенда-401».

Новые магнитофоны получили более качественный звук. Была снижена детонация, улучшено соотношение сигнал-шум, были основательно улучшены показатели усилителей, проведена оптимизация схемотехнических решений для «Спутник-401», даже предусмотрели использование второй скорости — 2,38 см/с.

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


Радиокассета


mp3 кассета

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

В 1974-м и 76-м годах последовали ещё две харьковские модернизации, они стали наиболее массовыми версиями “Десны” того периода — «Спутник-402» и «Спутник-403». Модели получили косметические и оптимизационные обновления, усовершенствованную схемотехнику. Неизменным оставалась лентопротяжная техника, скопированная с филипсовского первенца.

Можно смело утверждать, что последним устройством в семействе «Десны» стал «Спутник-404», который увидел свет в 1982 году. От американского прародителя из 60-х магнитофон традиционно позаимствовал лентопротяжную механику и компоновочную схему.

Запорожская “Весна”


Одной из знаковых и наиболее популярных в 70-е — 80-е линеек портативных магнитофонов стали устройства с названием “Весна”. Они также были созданы в Украинской ССР, которая в то время на ряду с большинством западных республик выполняла функцию всесоюзного сборочного цеха. Магнитофоны под брендом «Весна» производили на запорожском предприятии «Искра», а также на киевском заводе “Коммунист” (ныне “Радар”).


«Весна-305»

Первый кассетный магнитофон оригинальной конструкции (вероятно, первый советский портативный магнитофон “собственной” разработки) планировали выпустить в 1971-м. Им должно было стать устройство с двухскоростным бесколлекторным двигателем БДС с электронным управлением, которые до этого момента не выпускались в СССР.

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

Так на свет появился первый народный кассетник — «Весна-305». Через год киевляне доработали трехфазный бесколлекторный двигатель (названный БДС-0,2) и в Запорожье стартовал выпуск «Весна-306». Функциональным отличием устройств стало наличие у флагмана с бесколлекторным двигателем двух скоростей работы (4,76 и 2,38 см/с, соответственно).


«Весна-306»

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

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

Иными словами, магнитофоны этой линейки полюбились отнюдь не благодаря новому двигателю. Наиболее ценным эксплуатационным достоинством системы стал лентопротяжный механизм, который вопреки обыкновению не копировался с западных образцов, а создавался с нуля. Он был оборудован двумя идентичными маховиками, которые вращались в разные стороны и благодаря удвоенной массе существенно повышали стабильность протяжки ленты. Это особенно помогало при эксплуатации во время переноски. С 1976 г. полные аналоги “Весна 305” и ”Весна-306” изготавливались Пермским электроприборный заводом, они получили название «Ритм-301».

Стабильность и надежность механизма сделали его универсальной платформой, на базе которой были созданы другие советские магнитофоны «Романтик-306», «Электроника-311», «Электроника-323», «Квазар-303». Думаю, не будет ошибкой отнести эти устройства к семейству “Весна — 305 — 306”.

Отдельного внимания заслуживают характеристики ранних магнитофонов “Весна”, которые во многом превосходили нормы заявленного третьего класса:

  • Рабочий диапазон звуковых частот на линейном выходе при скорости 4,76 см/с — 63…10 000 Гц, при скорости 2,38 см/с — 63…5000 Гц.
  • Номинальная выходная мощность: 0,8 Вт.
  • Напряжение питания — 9 вольт (шесть элементов 373 или сеть переменного тока, блок питания встроенный),
  • Мгнитофон сохраняет работоспособность при падении напряжения до 5,1 В.
  • Габариты магнитофона — 242×242×68 мм.
  • Масса вместе с батареями 3,7 кг.
  • Цена на старте продаж достигала 195 рублей, к 1978-му году упала да 165 руб.

Продолжение “Весны”


Почти без изменений модели 305 и 306 выпускали до 1978 года, всего этих магнитофонов было произведено более 850 тысяч. Если верить статье в Википедии, то сегодня тяжело найти работоспособные экземпляры, так как надежная конструкция позволяла беспощадно расходовать эксплуатационный ресурс. На базе моделей 305 и и 306 в дальнейшем были разработаны функционально усовершенствованные модели «Весна-202» и «Весна-205», а также (в какой-то степени) магнитола «Весна-204».

В дальнейшем киевский “Коммунист” и запорожская “Искра” выпустили портативные стерео магнитофоны. «Весна-201 стерео» появилась в 1977-м году, в 1978-м — усовершенствованный вариант «Весна-211 стерео», который оборудовался более мощным усилителем и дополнительно стереопарой.

Для советского магнитофоностоения середины-конца 70-х годов это было не то чтобы прорывом, но успехом и показателем серьезного прогресса. Очередной этап для “Весны” наступил в 1985 году, когда начался выпуск линейки «Весна-310С» — магнитофонов с принципиально новой компоновочной схемой.

В дальнейшем идентичные устройства были успешно скопированы Рязанским приборным заводом и выходили также под маркой “Русь”.

Народный советский Grundig или просто “Электроника 301”


Рассказ о народном магнитофоне будет неполным без упоминания “Электроники 301“ (она же «Парус-301», разработки Московского завода “ТочМаш”.

Этот магнитофон, равно как и “Весна-305/306”, завоевал огромную популярность среди советских граждан благодаря высокой надежности в сочетании со сносными характеристиками. Его серийный выпуск был начат в 1972-м году. Традиционно модель была частично скопирована с магнитофона C100L, выпускавшегося компанией Grundig с 1966 по 1968-й годы.


«Парус 301»


Grundig C100L

Магнитофон получил износоустойчивый лентопротяжный механизм, электронную стабилизацию скорости, а также сравнительно неплохой усилитель на германиевых транзисторах. Уже через 2 года он был модернизирован до версии “Электроники 302“, с дизайном максимально близким к оригиналу и применением громкоговорителя 1ГД-40 вместо 0,5ГД-30, что улучшило верность воспроизведения.

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

Итог


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

Использован фотоконтент:
www.rw6ase.narod.ru
www.flickr.com/photos/41902337@N07
daxgarth.wordpress.com/2017/08/23/compact-cassette-proton-ussr
stereo.ru
www.radiomuseum.org/r/grundig_c100l.html
igrovoetv.online
(Если вы против использования ваших фото в нашем материале — напишите нам и мы их заменим)

Джинса
Мы торгуем электроникой. В нашем каталоге представлен широкий ассортимент аудио и видео аппаратуры, аксессуаров, коммутации.

Let's block ads! (Why?)

500 Гбит/с — рекорд скорости в оптоволоконных сетях

Инженерам из Германии удалось добиться рекордной скорости передачи данных по оптоволокну в реальных, не лабораторных, условиях — 500 Гбит/с в одном канале.


/ Flickr / Tony Webster / CC BY

Кто установил рекорд


По данным ОЭСР, через три года количество устройств интернета вещей может достигнуть 50 млрд. С ростом числа гаджетов вырастет и объем трафика в мобильных сетях — по некоторым оценкам, примерно в четыре раза. В Deloitte говорят, что существующая оптоволоконная инфраструктура, которая станет основой для 5G-сетей, не справится с подобной нагрузкой.

По этой причине все больше компаний и исследовательских организаций работают над технологиями, повышающими пропускную способность «оптики». Одной из таких организаций является Мюнхенский технологический университет (TUM). Его сотрудники еще пять лет назад разработали алгоритм вероятностного формирования сигнального созвездия — Probabilistic Constellation Shaping, или PCS (подробнее о нем расскажем далее). В 2016 году с её помощью удалось впервые достичь терабитной скорости передачи данных в лаборатории.

В феврале этого года та же группа ученых поставила другой рекорд — они осуществили передачу данных на скорости 500 Гбит/с, но сделали это в «полевых» условиях. Для тестов использовали сигнальный процессор Nokia PSE-3, который внедрили в сеть немецкого оператора M-Net.

Как работает алгоритм


PCS — это метод, который дополняет квадратурную амплитудную модуляцию (QAM) в оптоволоконных сетях. В классическом случае QAM все точки (значения амплитуды сигнала) имеют равные веса и используются с одинаковой частотой.

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

/ Wikimedia / Splash / CC BY-SA / Сигнальное созвездие для 16-QAM

Обычно PSC реже задействует сигнальные точки с большой амплитудой. По словам разработчиков, это позволяет повысить устойчивость сигнала к шумам и увеличить скорость передачи. Например, для 16-QAM «прирост» составляет от 15 до 43%.

Применение и потенциал технологии


По словам президента Nokia Bell Lab Маркуса Велдона (Marcus Weldon), в будущем PCS позволит оптоволоконным сетям передавать большие объемы данных и динамически адаптироваться под текущие потребности в трафике (например, в 5G-сетях).

Технологию уже поддерживает провайдер сетевого оборудования Infinera. Компания использует вероятностную модуляцию в цифровых сигнальных процессорах серии ICE. В Infinera заявляют, что устройства смогут увеличить пропускную способность сетей до 800 Гбит/с, но пока их возможности еще не были протестированы. Представители компании говорят, что технология поможет мобильным операторам и интернет-провайдерам сократить расходы на развитие инфраструктуры и строительство новых линий.

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

О чем мы пишем в нашем корпоративном блоге:


/ Flickr / Groman123 / CC BY-SA

Аналог вероятностной модуляции


Есть ещё один вид модуляции сигнального созвездия — геометрический. Он отличается от вероятностного тем, что меняет не частоту использования конкретной точки, а форму созвездия. Для этого к амплитудной модуляции сигнала добавляют фазовую, что позволяет «сдвинуть» точки относительно друг друга. Как и вероятностная модуляция, геометрическая помогает добиться более эффективного использования оптического канала: расположение точек в созвездии выбирается так, чтобы в каждой из них отношение сигнал/шум (SNR) было максимальным.

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

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

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

Дополнительное чтение в нашем блоге на Хабре:

Let's block ads! (Why?)

Redis вновь меняет лицензию

В Redis Labs уже второй раз за последние полгода меняют модель лицензирования для ряда своих продуктов. Сейчас компания переходит с Apache 2.0 Commons Clause на Redis Source Available License (RSAL). Поговорим о причинах этого решения и особенностях RSAL.


/ Pixino / congerdesign / PD

Немного истории


Redis Labs уже не первый раз меняет лицензию на свои продукты. В августе прошлого года компания перевела несколько модулей — Redis Graph, ReJSON и др. — с лицензии GNU AGPL на Apache 2.0 Commons Clause. Тем самым компания запретила продажу оригинальных модулей сторонними организациями. Однако это привело к неприятным последствиям.

Во-первых, новая лицензия стала причиной путаницы и непонимания. Некоторые пользователи ошибочно решили, что работа с модулями теперь регулируется только Apache 2.0 (без Commons Clause). Во-вторых, запрет на продажу решений Redis «нанес удар» по открытому ПО. К примеру, часть сервисов были вынуждены удалить разработчики Debian и Fedora. Им пришлось создавать форки репозиториев модулей Redis и объединять их в проект GoodFORM.

Команда Redis Labs также столкнулась с непредвиденными трудностями. Ограничения лицензии замедлили рост сообщества вокруг продуктов, хотя ожидалось, что эффект будет прямо противоположным. Всё это привело к тому, что в Redis Labs создали свою лицензию, заточенную под нужды и особенности компании — RSAL.

Что собой представляет новая лицензия


Согласно условиям RSAL, разработчики могут использовать модули RediSearch, RedisGraph, RedisJSON, RedisBloom, RedisML и несколько других в своих сервисах, менять исходный код и внедрять его в приложения. Bтоговые решения можно распространять и продавать.

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

Во всех остальных случаях разработанное ПО можно использовать и распространять с пометкой: This software is subject to the terms of the Redis Source Available License Agreement.

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


/ Flickr / Mark Hougaard Jensen / CC BY-SA

Что думает сообщество


Некоторые представители комьюнити полагают, что повторная смена лицензии может стать очередной ошибкой. Мэтт Эсей (Matt Asay) из Adobe не согласен с утверждением, что крупные корпорации, которые продают ПО на базе открытых продуктов, негативно влияют на развитие open source экосистемы. Он говорит, что такие организации, наоборот, помогают распространять открытые продукты на глобальном рынке, предавая им известность.

Видение Redis также не разделяет Гордон Хафф (Gordon Haff), глава подразделения облачных технологий в Red Hat. Он считает, что за счет лицензирования в Redis пытаются «усидеть на двух стульях» — получать прибыль от продажи модулей и быть open source компанией.

Apache-гуру из Red Hat Рич Боуэн (Rich Bowen) назвал решение компании «бессмысленным». По его мнению, люди, которые приходят в open source, ожидают увидеть бесплатные решения и им едва ли захочется разбираться в каких-то ограничениях и условиях. С ним согласны члены организации Open Source Initiative (OSI). Они заявляют, что действия Redis противоречат определению и принципам открытого ПО.

Есть и те, кто видит смысл в переходе на новую лицензию. Например, руководитель BaenCapital отмечает, что корпорации, которые выстраивают свои продукты на основе открытого ПО, поступают неэтично. Поэтому действия Redis вполне понятны — с помощью новых лицензий компания защищает свои интересы и права разработчиков.

Один из создателей Ansible Майкл Дехаан (Michael DeHaan) тоже считает, что если весь софт распространять бесплатно, большинство проектов просто не выживет. Не всем компаниям удается привлечь инвесторов, поэтому продажа отдельных компонентов крупным организациям — один из способов удержаться на рынке.

Кто еще недавно менял лицензию


Redis Labs — не единственные, кто пробует разные подходы к лицензированию. Так, в октябре 2018 MongoDB перешли с GNU AGPL на собственную версию GNU 3 — Server-Side Public License (SSPL). Цель смены лицензии та же, что и у Redis — не дать сторонним компаниям «упаковывать» и перепродавать открытую СУБД.

Авторы проекта Confluent тоже отказались от Apache 2.0 в пользу своего варианта — Confluent Community License. Условия новой лицензии запрещают продавать KSQL как проприетарное решение. Хотя реализовывать SaaS-сервисы на этом SQL-движке, все так же разрешено.

Есть и другие примеры компаний, где часть решений реализуют за деньги. Среди них — Elasticsearch, Hadoop, Berkeley DB и десятки других.

«Бесплатных проектов вроде Linux-ядра, WordPress или GIMP становится все меньше. Разработчики открытого ПО выстраивают бизнес-модели в попытке найти баланс между доходом и свободным распространением продуктов без ущерба для компании, — комментирует Сергей Белкин, начальник отдела развития провайдера виртуальной инфраструктура 1cloud.ru. — Но в ИТ-сообществе еще достаточно тех, кто выступает против изменений концепции open source. Поэтому в ближайшее время полностью свободное ПО не исчезнет с рынка, как бы ни менялись лицензии на отдельные продукты и их компоненты».

Посты из блога 1cloud.ru:

Let's block ads! (Why?)

[Из песочницы] Что спрашивают на собеседовании у джуна, или как я искала свою вторую работу в ИТ

Я работаю в сфере IT чуть более 1 года как Test Automation Engineer.

Мое базовое образование никак не способствовало этому, поскольку в моем дипломе написано “Логистик-Экономист”. Тернистный путь в IT я начала с бесплатных курсов при одной крупной компании в моем городе, после них поработала в той же компании на 2х проектах, после чего решила сменить место работы.

image
Я откликнулась на 8 вакансий, еще 4 компании написали мне сами (кадровые агентства не в счет, с ними общаться я не планировала).

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

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

Первая компания очень хотела найти сотрудника со знанием IP-нетворкинга, но таких специалистов на рынке, по их же словам, оказалось мало, поэтому пригласили и меня:) В основном на собеседовании спрашивали о Java: static, == / equals и другие типичные вопросы, которые я не успела записать, потому что идея написать эту статью пришла после второй компании, но они будут упоминаться в описании последующих собеседований. Также были попытки спросить про IP-нектворкинг, но довольно быстро стало понятно, что я в этом не сильна. Тем не менее, техническое интервью, со слов HR, прошло хорошо и меня пригласили поболтать по скайпу с заказчиком, которому не понравилось, что у меня не связанное с ИТ образование, и потому предложения не последовало.

Вторая компания — продуктовая — разработчик онлайн-игр. Кроме обычной работы с тестами частью функционала тестовой команды было написание и поддержка ботов для онлайн-игр. В общем-то команде нужен был специалист со знанием Python, что в итоге и стало основной причиной моего отказа. На собеседовании вопросы мне задавали по Java (тк другим языком не владею, о чем и предупредила по телефону), ниже приведу их списком:

  • Exceptions — какие бывают, иерархия
  • Команды Git — как сделать коммит и тд
  • Может ли блок finally не выполнятся?
  • Постулаты ООП с примерами
  • Что такое конструктор?
  • Как вызвать метод родительского класса в дочернем методе, если этот метод так же переопределен в дочернем методе?
  • написать xpath
  • решить задачку на алгоритмизацию
  • значения примитивных типов по умолчанию
  • ==/equals
  • Написать 2 SQL-запроса (первый содержал join, который я заменила вложенным запросом, второй — ключевые слова limit и desc)
  • слово final — все, что знаешь
  • описать, из чего состоит тест

А также блок про Selenium:
  • Page Object
  • Что такое локаторы
  • findElement и findElements — в чем разница и что будет, если в findElement передан локатор, который возвращает более одного объекта

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

Третья компания — аутсорсинговая, занимается созданием и поддержкой сайтов для одного авиаперевозчика. Тестовая команда использует связку Selenium+Maven+TestNG, и используя этот же подход мне необходимо было решить тестовую задачу, чтобы попасть уже на техническое интервью. Задача состояла в том, чтобы залогиниться на сайт (юзера создать вручную), открыть почту и проверить количество входящих писем, после чего свое решение прислать ссылкой на Git. Задача была решена, техническое интервью состоялось, вопросы были такие:

  • Разница между List и Set
  • Написать XPath
  • Try-catch-finally
  • ==/equals
  • Слово static
  • Static блок
  • Особенности FluentWait
  • Абстрактные классы и интерфейсы
  • (Внезапно) Что такое полиморфизм
  • (еще более внезапно) Методы класса Object
  • Page Object
  • Какие аннотации TestNG используются для обозначение входных данных
  • Как можно с помощью аннотаций указать последовательность выполнения тестов

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

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

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

Среди всех интервью это было, пожалуй, самое сложное. Например, привычное сравнение List и Set перешло в вопрос “В чем разница реализации метода get в ArrayList и LinkedList?”

Из банального были:

  • Иерархия коллекций (неплохо, конечно, было бы повторить перед собеседованием)
  • Слово Static
  • Наследование
  • Слово Super
  • Абстрактные классы и интерфейсы
  • Многопоточность — сразу сказала, что не знаю, и тем самым пресекла все вопросы

Спросили также про SQL, а именно: создавала ли я таблицы сама. Запросы писать не просили.

Кроме того, тут требовалось решить пару задач, одна на алгоритмизацию, а вторая, как оказалось, на знание такой штуки как new Command.execute() (мне любопытно, много ли человек сталкивались с этим).

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

На этом собеседовании важное место (минут 20) занимали вопросы про софт скилы, про конфликты, работу в команде и т.д.

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

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

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

image

А еще мы сами можем не подозревать о своих сильных сторонах.

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

Let's block ads! (Why?)

[Из песочницы] novtable оптимизация


Компилятор Microsoft позволяет добавить расширение «novtable» для атрибута «__declspec» при объявлении класса.

Заявленная цель — значительно уменьшить размер генерируемого кода. На экспериментах с нашими компонентами уменьшение составило от 0,6 до 1,2 процента от размера DLL.

Применимость: классы, не предназначенные для создания экземпляров напрямую из них.

Например: чисто интерфейсные классы.

В коде это выглядит так:

struct __declspec(novtable) IDrawable
{
        virtual void Draw() const = 0;
};


Примечание: ключевое слово struct использовалось для декларации интерфейсного класса, чтобы избавить пример от не относящихся к теме статьи деталей; тогда как в случае использования class пришлось бы использовать public для указания «публичности» методов. По той же причине я не буду в этой статье добавлять виртуальный деструктор в интерфейсный класс.

Название «novtable» обещает, что виртуальной таблицы не будет… Но как же работает механизм вызова виртуальных функций в следующем коде:

// Добавим декларацию прямоугольника, реализующего интерфейс IDrawable:

class Rectangle : public IDrawable
{
        virtual void Draw() const override
        {
        }

        int width;
        int height;
};

…
IDrawable* drawable = new Rectangle;
drawable->Draw(); // происходит вызов Rectangle::Draw
…


Вспомним, что добавляется при объявлении виртуальной функции в классе:
  1. Определение таблицы виртуальных функций. Используется один экземпляр этой таблицы для всех экземпляров класса.
  2. В члены данных класса добавляется указатель на таблицу виртуальных функций.
  3. Код по инициализации этого указателя в конструкторе класса.

Таким образом, в нашем примере будет существовать декларация двух таблиц виртуальных функций: для IDrawable и для Rectangle. При создании объекта Rectangle первым выполняется конструктор IDrawable, который инициализирует указатель на свою таблицу виртуальных функций. Схематично это выглядит так:


Так как функция draw в IDrawable объявлена чисто-виртуальной (указано "=0" вместо тела функции), то в таблице виртуальных функций записан адрес генерируемой компилятором функции purecall.

Затем выполняется конструктор Rectangle, который инициализирует тот же указатель, но на свою таблицу виртуальных функций:


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

В этом случае при конструировании IDrawable указатель на таблицу виртуальных функций будет содержать непредсказуемое значение. Но это не должно нас беспокоить, так как создание реализации с обращением к виртуальным функциям до полного конструирования объекта, как правило, является ошибкой. Если, например, в конструкторе базового класса вызывать невиртуальную функцию этого класса, которая в свою очередь вызывает виртуальную функцию, то без novtable будет вызвана функция purecall, а с novtable — будет непредсказуемое поведение; ни один из вариантов не может быть приемлемым.

Заметим, что происходит не только уменьшение размера, но и некоторое ускорение работы программы.


Как известно, std::dynamic_cast позволяет приводить указатели и ссылки одного экземпляра класса к указателю и ссылке на другой, если эти классы связаны иерархией и являются полиморфными (содержат таблицу виртуальных функций). В свою очередь оператор typeid позволяет получать в runtime информацию об объекте по переданному ему указателю (ссылке) на этот объект. Эти возможности обеспечиваются механизмом RTTI, который использует информацию о типах, расположенную с привязкой к vtable класса. Детали структуры и расположения зависят от компилятора. В случае компилятора Microsoft схематично это выглядит так:

Поэтому если при сборке компилятору приказано включить RTTI, то novtable исключает еще и создание определения type_info для IDrawable и требуемых для нее служебных данных.
Заметим, что если у вас каким-то образом обеспечивается знание, что приводимый указатель (ссылка) на базовый класс указывает на реализацию производного, то std::static_cast эффективнее и не требует RTTI.


Помимо MSVC, данная возможность с тем же самым синтаксисом присутствует в Clang при компиляции под Windows.
  1. __declspec(novtable) — никак не влияет на объем памяти, занимаемый экземплярами класса.
  2. Уменьшение размера и некоторое ускорение работы программы обеспечивается за счет исключения определения неиспользуемых таблицы виртуальных функций, служебных данных RTTI и исключения кода инициализации указателя на таблицу виртуальных функций в конструкторах интерфейсных классов.

Let's block ads! (Why?)