Ничего не начинает. Меня за 30 с лишним лет карьеры, кажется, один раз спросили про диплом. Причём это была довольно мутная контора, но ее начальник был доцентом или профессором или что-то в этом роде, и, видимо, очень этим гордился.
Невозможно напрямую просматривать необработанные записи каталога, поскольку файловая система управляет ими на низком уровне
Возможно. Можно открыть директорию на чтение, как файл и хоть обчитаться. Проблема в том, что формат прочтённого оттуда зависит от типа файловой системы, чтобы с этим не заморачиваться, существует opendir и т.п.
Это зеркальная копия оригинального файла.
Я б подчеркнул, что все жесткие ссылки совершенно равноправны, на них никак не отмечено, какая из них была оригиналом.
при создании нескольких жёстких ссылок на один файл не тратится лишнее место на диске.
При создании символических ссылок его тратится не сильно больше. Символическая ссылка - это маленький текстовый файл, а на современных файловых системах содержимое маленьких файлов хранится прямо в i-node и не требует дополнительных блоков.
жёсткие ссылки обычно срабатывают быстрее мягких
Там всё это настолько агрессивно кешируется, что на практике разница невелика
При создании символических ссылок следует указывать абсолютный путь, поскольку относительные пути не будут работать.
Будут работать, но отсчитываюся они не от текущего каталога, а от той директории, в которой живет символическая ссылка.
Иногда это хорошо, иногда не очень. Например, если ссылки относительные, то целую иерархию директорий, содержащую ссылки и то, на что они ссылаются, можно перенести в другое место и ничего не сломается. Но если перенести в другое место директорию, содержащую ссылку, а не то, на что она ссылается, то относительная ссылка может сломаться, а абсолютная - нет.
Поскольку связь мягкой ссылки является логической, а не дублированием, символические ссылки могут указывать на целые каталоги или на файлы на удалённых компьютерах. Жёсткие ссылки для этого не предназначены
Это чисто волевое решение из 1970-х, запретить жестким ссылкам ссылаться на директории, чтобы избежать необходимости в программах, работающих с директориями, реализовывать логику, учитывающую возможность организовать цикл.
Но с появлением символических ссылок и bind mount эту логику всё равно пришлось написать (или смириться с вожможностью зацикливания), поэтому это ограничение теперь - просто такой технический артефакт, оставшийся нам от времен динозавров.
Низкие издержки: размер файлов символических ссылок небольшой, так как они содержат только путь к цели.
А выше говорилось, что низкие издержки присущи жестким ссылкам :)
Небезопасность: если ими неправильно управлять, мягкие ссылки могут представлять угрозу безопасности, так как могут указывать на конфиденциальные файлы.
Они не дают доступа к файлу. Правда, они могут раскрывать сам факт существования такого файла и его название. Например, если файл называется "Приказ об увольнении Иванова И.И.doc", то о чём он, понятно и без заглядывания внутрь...
Разные индексные дескрипторы: мягкие ссылки имеют собственные айноды, из-за чего количество айнодов в системе может слишком увеличиться.
Иноды дёшевы. В хорошо настроенной системе их с запасом. А на некоторых файловых системах они просто выделяются динамически, по мере надобности, и делят место со всеми остальными запчастями ФС.
Проблема в том, что все эти прекрасные принцыпы - это мысли зрелых разработчиков, адресованные зрелым разработчикам.
Вот взять, к примеру, програмку, которая делает что-нибудь полезное по HTTP (и вовсе не обязательно это веб-бровсер). Где тут проводить границы single responsibility?
Вот я бы, наверное, провёл их по линии, очерченной соответствующим набором RFC, вынеся MIME и IDA в отдельные сущности, по границам, очерченным тамошними RFC. Но можно ведь всё в одну сущность затолкать, а можно и наоборот, помельче разрезать. Какое тут правильное решение? На этот вопрос нет простого однозначного ответа.
Или, например, идея распилить класс Biathlete на три, каждый из которых имеет свою реализацию метода train(). Нередко это приводит к тому, что класс, который так бы уместился в 200 простых и понятных строк превращается в иерархию классов, общим объёмом строк на тысячу, которые рано или поздно обрастают дублирующимся кодом и которые надо все параллельно поддерживать.
А так ли уж по сути отличаются тренировки для юниоров, зрелых и престарелых? Может, они в целом примерно одинаковые, но отличаются набором параметров? А что, если "думательную" часть класса сделать общую, и кормить ее табличкой с параметрами, которые специализируют её под контретное применение?
Ну и т.д. и т.п.
И, к сожалению, все эти прекрасные принципы, примененные без соответствующего опыта, пораждают, скорее, не хороший дизайн, а некоторый карго-культ...
Говорят, в Gnome используется visual recognition для тестирования экранного отображения.
Мы сейчас в OpenPrinting работаем над аналогичным проектом для тестирования преобразования изображения фильтрами при печати.
Так что похоже, это постепенно становится main stream...
Но попиксельно сравнивать в бровсере, такое себе. Тут надо бы проверять, что структура картинки соответствует ожидаемому. А расхождения на уровне пикселей могут зависеть от фонтов, видеокарты. Наверное, даже особенности реализации floating point math на целевой платформе могут на это повлиять.
C - это продукт работы ровно тех же людей, что и Go
Фреймворк - это такая штука, которая не просто полезная библиотека, а всю жизнь под себя подчиняет. В Go нет фреймворков потому, что библиотеки удобно интегрируются вокруг функций и интерфейсов, предоставляемых стандартной библиотекой. Можно сказать, что Go stdlib - это и есть такой фреймворк.
А там уже починили невозможность держать более одного экземпляра гошного рантайма в одном процессе.
Раньше это выглядело так: пишешь на Go DLL-ку. Грузишь её в сишную програмку. Работает. Грузишь в гошную програмку - причудливо глючит. Причем на разных платформах (я пробовал x86 линух и венду) по-разному. Гошные рантаймы main-а и DLL-ки не поделили процес...
Казалось бы, в этом примере можно было бы при кодировании пройтись по слайсу ID-ёв два раза: первый раз, чтобы подсчитать потребный размер буфера, потом сразу выделить буфер нужного размера и вторым проходом закодировать. И можно было бы обойтись без bytes.Buffer и реаллокаций...
Выглядит, если честно, не очень убедительно. Вы же осилили гошный псевдоассемблер, Можно было бы на нём написать SIMD-овские фрагменты, задекларировать, как гошную функцию и звать по указателю, который инициализируется при старте. Вызов псевдоассемблера из Go - вещь недорогая, сами знаете.
структуры поверх типов а ля [13]byte и каждый раз при обращении к полю кастить его через unsafe
Или написать type MyType [13]byte и методы к нему, которые предоставляют доступ к полям логической структуры, а сами работают напрямую с этими 13-ю байтами...
Да, написать всё на C++ очевидно было бы эффективнее
Да и не факт. C++-ные программы имеют тенденцию активно создавать короткоживущие объекты в куче (строки, вектора, ...). Но куча в C++ ощутимо медленнее, чем в Go...
Написали Вы, наверное, примерно то же, что и я. Но вот понял я Ваш текст при беглом чтении так, что в случае вызова CGo новый поток создаётся всегда, но не сразу по месту, а асинхронно.
Насколько я понимаю, CGo call не создаёт поток операционной системы, но говорит планировщиуку Go, что текущий поток не надо учитывать, если возникнет вопрос о создании нового, потому что он ушел в Си, и никто не знает, вернётся ли.
Но вот будет ли на самом деле создан новый поток - вопрос потребностей. В данном случае лишь временно поднимают квоту.
Когда появился UNIX, его ядро (да и вся система) была написана на C. В те времена операционные системы было принято писать на асме. Пайк ходил, всем рассказывал на голубом глазу, что C почти не уступает ассемблеру по производительности, но значительно выигрывает по удобству разработки, надёжности/анализируемости получающегося кода и проч. В те времена C проигрывал асму по скорости раза в два.
Однако практика показала их стратегическую правоту.
Сейчас с Go повторяется та же история. И тот же Пайк ходит, всем рассказывает (ну, вернее, рассказывал. Он, вроде, на пенсию вышел), что Go мало чем уступает C по производительности. Хотя когда компилятор Go переписали с C на Go, он вроде замедлился как раз в те же волшебные два раза.
Посмотрим, что покажет практика, но на это уйдет какое-то время.
С другой стороны, Go не такой уж и медленный. Мне тут понадобилось картинки масштабировать, причем желательно по строкам, а не заливать сразу всю картинку в память. Поэтому готовые решения не подошли, и пришлось написать своё. В общем, довольно наивно написанная реализация на Go показывает скорость, сравнимую с ImageMagic (хотя сишные реализации бывают и побыстрее. Они, правда, норовят все ядра процессора занять, а я не уверен, что в моём случае это достоинство).
Люди, которые дизайнили Go, наверное, наполовину определили развитие ИТ-индистрии в том виде, как мы её имеем.
UNIX, C - их рук дело. Контейнеризация, столь популярная сегодня, во многом основана на идеях из Plan9, которая тоже их рук дело. Сама по себе идея писать системное ПО, включая ядро ОС, на языке высокого уровня, а не на ассемблере - их рук дело.
Go тоже возник не на пустом месте. Он - прямой наследник языка Alef, диалекта C, созданного специально для написания Plan9.
В общем, мне кажется, Ваше высказывание несколько слишком категорично...
Если одно прерывание относится к разным драйверам, на каждом из них лежит ответственность "сбросить" свою причину для возникновения прерывания.
Если драйвер этого не сделает, прерывание будет приходить снова и снова.
Можно, конечно, сделать автодетект spurious interrupts, и отшибать захрясшее прерывание. Но при ложном срабатывании есть шанс заодно отстрелить ни в чём не повинное устройство, которому не повезло оказаться на том же прерывании.
Вот, даже в линуксе такое происходит, даже на очень обкатанном железе, а не на какой-то экзотике (интеловский чипсет, встроенный в него контроллер I2O, на нём висит совершенно стандартный тачпад). Приходится даже иногда делать неприятные костыли, типа этого:
Ничего не начинает. Меня за 30 с лишним лет карьеры, кажется, один раз спросили про диплом. Причём это была довольно мутная контора, но ее начальник был доцентом или профессором или что-то в этом роде, и, видимо, очень этим гордился.
Очень спорное заявление.
Возможно. Можно открыть директорию на чтение, как файл и хоть обчитаться. Проблема в том, что формат прочтённого оттуда зависит от типа файловой системы, чтобы с этим не заморачиваться, существует
opendirи т.п.Я б подчеркнул, что все жесткие ссылки совершенно равноправны, на них никак не отмечено, какая из них была оригиналом.
При создании символических ссылок его тратится не сильно больше. Символическая ссылка - это маленький текстовый файл, а на современных файловых системах содержимое маленьких файлов хранится прямо в i-node и не требует дополнительных блоков.
Там всё это настолько агрессивно кешируется, что на практике разница невелика
Будут работать, но отсчитываюся они не от текущего каталога, а от той директории, в которой живет символическая ссылка.
Иногда это хорошо, иногда не очень. Например, если ссылки относительные, то целую иерархию директорий, содержащую ссылки и то, на что они ссылаются, можно перенести в другое место и ничего не сломается. Но если перенести в другое место директорию, содержащую ссылку, а не то, на что она ссылается, то относительная ссылка может сломаться, а абсолютная - нет.
Это чисто волевое решение из 1970-х, запретить жестким ссылкам ссылаться на директории, чтобы избежать необходимости в программах, работающих с директориями, реализовывать логику, учитывающую возможность организовать цикл.
Но с появлением символических ссылок и bind mount эту логику всё равно пришлось написать (или смириться с вожможностью зацикливания), поэтому это ограничение теперь - просто такой технический артефакт, оставшийся нам от времен динозавров.
А выше говорилось, что низкие издержки присущи жестким ссылкам :)
Они не дают доступа к файлу. Правда, они могут раскрывать сам факт существования такого файла и его название. Например, если файл называется "Приказ об увольнении Иванова И.И.doc", то о чём он, понятно и без заглядывания внутрь...
Иноды дёшевы. В хорошо настроенной системе их с запасом. А на некоторых файловых системах они просто выделяются динамически, по мере надобности, и делят место со всеми остальными запчастями ФС.
Проблема в том, что все эти прекрасные принцыпы - это мысли зрелых разработчиков, адресованные зрелым разработчикам.
Вот взять, к примеру, програмку, которая делает что-нибудь полезное по HTTP (и вовсе не обязательно это веб-бровсер). Где тут проводить границы single responsibility?
Вот я бы, наверное, провёл их по линии, очерченной соответствующим набором RFC, вынеся MIME и IDA в отдельные сущности, по границам, очерченным тамошними RFC. Но можно ведь всё в одну сущность затолкать, а можно и наоборот, помельче разрезать. Какое тут правильное решение? На этот вопрос нет простого однозначного ответа.
Или, например, идея распилить класс
Biathleteна три, каждый из которых имеет свою реализацию методаtrain(). Нередко это приводит к тому, что класс, который так бы уместился в 200 простых и понятных строк превращается в иерархию классов, общим объёмом строк на тысячу, которые рано или поздно обрастают дублирующимся кодом и которые надо все параллельно поддерживать.А так ли уж по сути отличаются тренировки для юниоров, зрелых и престарелых? Может, они в целом примерно одинаковые, но отличаются набором параметров? А что, если "думательную" часть класса сделать общую, и кормить ее табличкой с параметрами, которые специализируют её под контретное применение?
Ну и т.д. и т.п.
И, к сожалению, все эти прекрасные принципы, примененные без соответствующего опыта, пораждают, скорее, не хороший дизайн, а некоторый карго-культ...
Говорят, в Gnome используется visual recognition для тестирования экранного отображения.
Мы сейчас в OpenPrinting работаем над аналогичным проектом для тестирования преобразования изображения фильтрами при печати.
Так что похоже, это постепенно становится main stream...
Но попиксельно сравнивать в бровсере, такое себе. Тут надо бы проверять, что структура картинки соответствует ожидаемому. А расхождения на уровне пикселей могут зависеть от фонтов, видеокарты. Наверное, даже особенности реализации floating point math на целевой платформе могут на это повлиять.
Всегда думал что эти самые базы сотрудники сами и выносят за небольшую мзду.
Некоторую сумму денег он точно удалит
C - это продукт работы ровно тех же людей, что и Go
Фреймворк - это такая штука, которая не просто полезная библиотека, а всю жизнь под себя подчиняет. В Go нет фреймворков потому, что библиотеки удобно интегрируются вокруг функций и интерфейсов, предоставляемых стандартной библиотекой. Можно сказать, что Go stdlib - это и есть такой фреймворк.
PL/1, наверное...
А там уже починили невозможность держать более одного экземпляра гошного рантайма в одном процессе.
Раньше это выглядело так: пишешь на Go DLL-ку. Грузишь её в сишную програмку. Работает. Грузишь в гошную програмку - причудливо глючит. Причем на разных платформах (я пробовал x86 линух и венду) по-разному. Гошные рантаймы main-а и DLL-ки не поделили процес...
Казалось бы, в этом примере можно было бы при кодировании пройтись по слайсу ID-ёв два раза: первый раз, чтобы подсчитать потребный размер буфера, потом сразу выделить буфер нужного размера и вторым проходом закодировать. И можно было бы обойтись без
bytes.Bufferи реаллокаций...Выглядит, если честно, не очень убедительно. Вы же осилили гошный псевдоассемблер, Можно было бы на нём написать SIMD-овские фрагменты, задекларировать, как гошную функцию и звать по указателю, который инициализируется при старте. Вызов псевдоассемблера из Go - вещь недорогая, сами знаете.
Или написать
type MyType [13]byteи методы к нему, которые предоставляют доступ к полям логической структуры, а сами работают напрямую с этими 13-ю байтами...Да и не факт. C++-ные программы имеют тенденцию активно создавать короткоживущие объекты в куче (строки, вектора, ...). Но куча в C++ ощутимо медленнее, чем в Go...
Написали Вы, наверное, примерно то же, что и я. Но вот понял я Ваш текст при беглом чтении так, что в случае вызова CGo новый поток создаётся всегда, но не сразу по месту, а асинхронно.
Насколько я понимаю, CGo call не создаёт поток операционной системы, но говорит планировщиуку Go, что текущий поток не надо учитывать, если возникнет вопрос о создании нового, потому что он ушел в Си, и никто не знает, вернётся ли.
Но вот будет ли на самом деле создан новый поток - вопрос потребностей. В данном случае лишь временно поднимают квоту.
Go придумал Роберт Пайк из AT&T и убедил Гугль профинансировать проект. Вероятно в обмен на то, что название языка будет напоминать слово "Google"
В статье много интересных технических деталей, но у меня всё-таки так и не сложилась ясная картина, куда CGo целые 70ns на вызов девает...
И жалко, что нет цифер для x86 - чтобы можно было сопоставить с собственным опытом на более привычной/распространённой платформе.
Когда появился UNIX, его ядро (да и вся система) была написана на C. В те времена операционные системы было принято писать на асме. Пайк ходил, всем рассказывал на голубом глазу, что C почти не уступает ассемблеру по производительности, но значительно выигрывает по удобству разработки, надёжности/анализируемости получающегося кода и проч. В те времена C проигрывал асму по скорости раза в два.
Однако практика показала их стратегическую правоту.
Сейчас с Go повторяется та же история. И тот же Пайк ходит, всем рассказывает (ну, вернее, рассказывал. Он, вроде, на пенсию вышел), что Go мало чем уступает C по производительности. Хотя когда компилятор Go переписали с C на Go, он вроде замедлился как раз в те же волшебные два раза.
Посмотрим, что покажет практика, но на это уйдет какое-то время.
С другой стороны, Go не такой уж и медленный. Мне тут понадобилось картинки масштабировать, причем желательно по строкам, а не заливать сразу всю картинку в память. Поэтому готовые решения не подошли, и пришлось написать своё. В общем, довольно наивно написанная реализация на Go показывает скорость, сравнимую с ImageMagic (хотя сишные реализации бывают и побыстрее. Они, правда, норовят все ядра процессора занять, а я не уверен, что в моём случае это достоинство).
Добавлю к высказыванию предыдущего оратора.
Люди, которые дизайнили Go, наверное, наполовину определили развитие ИТ-индистрии в том виде, как мы её имеем.
UNIX, C - их рук дело. Контейнеризация, столь популярная сегодня, во многом основана на идеях из Plan9, которая тоже их рук дело. Сама по себе идея писать системное ПО, включая ядро ОС, на языке высокого уровня, а не на ассемблере - их рук дело.
Go тоже возник не на пустом месте. Он - прямой наследник языка Alef, диалекта C, созданного специально для написания Plan9.
В общем, мне кажется, Ваше высказывание несколько слишком категорично...
Возникает проблема с разделяемыми прерываниями
Если одно прерывание относится к разным драйверам, на каждом из них лежит ответственность "сбросить" свою причину для возникновения прерывания.
Если драйвер этого не сделает, прерывание будет приходить снова и снова.
Можно, конечно, сделать автодетект spurious interrupts, и отшибать захрясшее прерывание. Но при ложном срабатывании есть шанс заодно отстрелить ни в чём не повинное устройство, которому не повезло оказаться на том же прерывании.
Вот, даже в линуксе такое происходит, даже на очень обкатанном железе, а не на какой-то экзотике (интеловский чипсет, встроенный в него контроллер I2O, на нём висит совершенно стандартный тачпад). Приходится даже иногда делать неприятные костыли, типа этого:
https://github.com/alexpevzner/hotfix-kvadra-touchpad