Это статья об основах программирования на Go. На канале я рассказываю об опыте перехода в IT с нуля, структурирую информацию и делюсь мнением.
Хой! Джедаи и Амазонки!
В первой части статьи - разбор кода записи строки через буфер обмена в файл .txt. Во второй части расскажу о хранении информации в компьютере и объясню, почему согласно СИ, 1 КБ не равен 1024 байт.
Эта информация будет полезна для понимания разницы записи строк напрямую в файл и записи в файл через буфер обмена.
Запись в .txt через буфер
В предыдущем посте я рассказывал о записи строк напрямую в файл. Сейчас посмотрим как это сделать через буфер обмена:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Create("SomeProject.txt")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
writer := bufio.NewWriter(file)
writer.WriteString("May the Force be with us")
writer.WriteString("\n")//перенос каретки
writer.WriteRune('S')//запись руны
writer.WriteString("\n")
writer.WriteByte(65)//запись байт - см. таблицу кодировки ASCII
writer.WriteString("\n")
writer.Write([]byte{80, 81, 92})
writer.WriteString("\n")
writer.Flush()
}
В коде мы использовали три пакета: fmt, os, bufio. Что здесь интересного. Есть четыре метода записи в буфер, в коде выше использованы все четыре:
- WriteString(): записывает строку
- WriteRune(): записывает один объект типа rune
- WriteByte(): записывает один байт
- Write(): записывает срез байтов
bufio.NewWriter() - функция создания потока вывода через буфер обмена.
writer.Flush() - метод сбрасывает информацию в файл и очищает буфер обмена.
Код выше ничего не выведет в терминал, только запишет информацию в лог-файл:
Если хотим увидеть результат работы программы в терминале, добавим фрагмент кода после метода writer.Flush():
file, err = os.Open("SomeProject.txt")
if err != nil{
fmt.Println("Не смогли открыть файл,", err)
return
}
defer file.Close()
buffer := make([]byte, 155)
_, err = file.Read(buffer)
if err != nil {
fmt.Println("Не смогли прочитать последовательность байт из файла,", err)
return
}
fmt.Println(string(buffer))
Результат выполнения программы будет следующий:
Что во второй части кода интересного: мы создали переменную, которая задаёт, какую часть информации выводить в терминал: buffer := make([]byte, 155). 155 в данном случае - размер выводимой строки, можно его уменьшить или увеличить. Давайте уменьшим до 28 и посмотрим, что выйдет:
При этом в самом файле информация сохранилась в полном объёме
Ну и к слову, переменные file (в коде фрагмент file, err...) связана со строками кода:
- defer file.Close()
- writer := bufio.NewWriter(file)
- _, err = file.Read(buffer)
Т.е. file - это имя переменной, и может быть каким угодно. Главное, чтобы понимали, что эта переменная file связана с функцией Create пакета os.
Такая же ситуация с переменной writer (в коде writer := bufio.NewWriter(file)), она связана со следующими строками кода:
- writer.WriteString("May the Force be with us")
- writer.WriteString("\n")
- writer.WriteRune('S')
- и т.д.
Переменные file или writer можно назвать как угодно, но логичнее именно так, см. статью "Читаем чистый код".
Теперь, когда разобрались с записью строк в файл напрямую и записью строк в файл через буфер, смоделируем ситуацию:
у нас 100 000 строк. Каждую нужно записать в файл.
Какой способ использовать - напрямую в файл, или через буфер? Если в файл напрямую, это 100 000 обращений к файлу. Ну и ладно, сто так сто - можно сказать. В общем, сходу непонятно, что лучше. Разберём теорию.
Хранение данных
В компьютере есть постоянная память (ПЗУ) и переменная/оперативная (ОЗУ, она же RAM). При работе с оперативной памятью, процессор получает информацию из неё намного быстрее, чем из ПЗУ.
ПЗУ
Два основных вида:
- SSD - "твердотельные диски";
- HDD - "жёсткие диски".
Если HDD называли жёстким диском, то потому что в нём был этот самый тяжёлый вращающийся диск. В SSD вращающихся частей нет - только микросхемы памяти, контроллеры, преобразователи и другая электроника. Данные в SSD обрабатываются намного быстрее, чем в HDD.
Помимо SSD и HDD, есть SAN - сетевые хранилища данных, комбинация аппаратного и программного обеспечения. В статье я не рассказываю о SAN, просто полезно знать, что есть и такая система хранения информации.
Скорость ПЗУ
Существует линейное чтение/запись данных и запись/чтение блоками. Я с этими терминами пока не разбирался детально, важно знать - что скорость операций с "блочными" данными меньше линейной скорости - в которой чтение или запись происходит с данными больших размеров, расположенных последовательно.
Ниже укрупнённая информация по различным моделям HDD и SDD для линейного чтения/записи, т.е. условий, близких к идеальным.
Скорость SSD примерно в пять раз быстрее HDD:
- Запись SSD - 460 Мбайт/с, HDD - 96 Мбайт/с;
- Чтение SSD - 550 Мбайт/с, HDD - 120 Мбайт/с.
Современные модели SSD могут иметь скорость чтения намного большую - до 7 000 Мбайт/с.
Что такое эти 96 или 550 Мбайт/с? Это пропускная способность.
Пропускная способность - объем информации, который память может обработать за секунду времени. Пример - скачиваем файлы с флешки.
SSD можно сравнить с флешкой. По-сути, это флешка и есть, только понавороченнее и пошустрее. HHD по устройству работы ближе всего к граммофону и виниловой пластинке.
От скорости вращения диска в HDD зависит скорость его работы. При вращении 5400 об./мин., HDD скорость считывания данных как правило будет около 100 Мбайт/с, а при 7200 около 150 Мбайт/с. Есть и более шустрые HDD.
Чтобы считать/записать данные в SSD, не нужно физически ничего вращать и перемещать.
ОЗУ
Оперативная память отвечает за работу приложений, которые запущены на компьютере. Один браузер со множеством вкладок или Photoshop с его слоями, может съесть памяти похлеще, чем современный шутер.
Важная характеристика ОЗУ - тактовая частота. Тактовая частота ОЗУ связана с процессором. У процессора есть ограничение - с какой максимальной тактовой частотой ОЗУ он может работать. Если установить более шуструю ОЗУ в комплекте с процессором, который её не потянет, процессор если и будет работать - то не-по максимуму. Или не будет работать вовсе, даже не запустится.
Тактовая частота важна не только для совместимости с процессором или с материнской платой. Тактовая частота ОЗУ - её ключевая характеристика. Многие приложения получают существенный прирост в производительности с ростом тактовой частоты. Типичный пример - архивация: чем выше частота модуля ОЗУ, тем шустрее процесс архивации/распаковки.
Сейчас поподробнее познакомимся с буфером обмена (далее - БО).
Бу́фер обме́на (англ. clipboard) — промежуточное хранилище данных, предоставляемое ПО и предназначенное для переноса или копирования информации между приложениями или частями одного приложения через операции вырезать, копировать или вставить.
Работая за компьютером, мы можем десятки раз за день использовать БФ и не задумываться о нём.
Суть в чём - когда мы сохраняем информацию в БО, информация попадает в ОЗУ - т.е. скорость записи и чтения из неё огромна. Логичный вопрос - огромная - это сколько?
Ниже информация для моего ноутбука 2012 года выпуска.
Скорость ОЗУ
- Чтение из памяти - 13401 Мбайт/с;
- Запись в память - 23876 Мбайт/с
- Копирование в память - 13261 Мбайт/с
- Задержка памяти - 44,7 наносекунды
Непонятно почему запись в память почти вдвое выше чтения, обычно происходит наоборот.
ОЗУ 2012 г. вдвое быстрее современных SSD дисков со скоростью чтения до 7000 Мбайт/с.
По частоте ОЗУ можно укрупнённо найти пропускную способность модуля памяти. Для этого нужно частоту модуля ОЗУ в мегагерцах умножить на восемь (бит), и получим ориентировочную скорость в Мбайт/с.
Так, для планки с частотой 1600 МГц, пропускная способность будет равна:
~ 1600 х 8 = 12 800 Мбайт/с
Чтобы узнать тактовую частоту ОЗУ, достаточно в командную строку (для Windows) ввести wmic memorychip get speed
Всё верно, два модуля по 1600 МГц. И по расчёту 12800 очень похоже на данные из ПО Everest - 13401.
Также можно посмотреть, в каком слоте находится модуль ОЗУ: в командную строку написать wmic memorychip get speed,devicelocator
Либо для определения частоты ОЗУ можно воспользоваться ПО, например, бесплатной утилитой CPU-Z.
Частота указана какая-то странная - 802,1 МГц. Не в том плане, что она дробная - она скачет, как нагрузка на процессор в диспетчере задач, например. И через секунду будет 798.5, например.
Почему в командной строке показаны два значения по 1600, а тут ~800 МГц?
Дело в том, что DDR (а у меня ОЗУ DDR) - вид ОЗУ, который относится к виду динамической синхронной памяти с удвоенной скоростью передачи данных. Удвоение скорости выполнено за счёт нового способа считывания команд: распознаёт команды по фронту и спаду тактового сигнала. И хотя работает при 800 МГц, выдаёт эффективность, сопоставимую с 1600 МГц для SDR. SDR был стандартом ОЗУ в прошлом.
CPU-Z выдаёт истинную частоту ОЗУ, а CMD (командная строка) - эффективную частоту ОЗУ.
Что если взять современные модули ОЗУ с тактовой частотой 3200 МГц. В ней по формуле, пропускная способность будет равна 3200 х 8 = 25 600 Мбайт/с. Нужно будет поподробнее протестить это уравнение, думаю здесь есть подводные камни. Т.к. видел тесты, которые показывали скорость чтения под 50 000 Мбайт/с - там должны быть модули ОЗУ с тактовой частотой 6250 МГц.
Ладно, осталось выяснить, 12800 Мбайт/с или 25600 Мбайт/с - это сколько? С секундами всё понятно, а с единицей измерения Мбайт- что это. К тому же ещё встречаются обозначения Мб, МБ, Мбит - разбираемся.
Единицы количества информации
Согласно ГОСТ 8.417-2002 "Единицы величин", где рассказывается об СИ и других единицах измерения, сокращением МБ обозначают 10^6, а не 2^20.
Краткий вывод: верно обозначать МБ или Мбайт. Мбит - тоже верно, но мы помним: 8 Мбит = 1 МБ = 10^6 байт.
В 2015 году вышел ещё один стандарт - ГОСТ IEC 60027-2-2015 «Обозначения буквенные, применяемые в электротехнике. Часть 2. Электросвязь и электроника». Стандарт закрепляет термин мебибит (мегабинарный):
1 МиБ = 2^20 бит
На практике до сих пор может возникать путаница. А иногда - это может выглядеть, как маркетинговый ход.
100 Мбит/с - это не 100 мегабайт в секунду, а 12,5 мегабайт в секунду.
Единицы количества информации по ГОСТ представлены в таблице ниже:
Выводы
Способ записи информации в файл через буфер обмена может быть выгоден, т.к. буфер (он же ОЗУ), работает намного быстрее, чем твердотельное хранилище.
Используется два подхода при записи данных в файл:
- Пишем сразу в файл;
- Пишем сначала в буфер (в ОЗУ), потом записываем в содержимое буфера в файл.
Остальное - вариации на тему работы с буфером.
Применение
Так как обращение к файловой системе - операция медленная, выбираем вариант записи так:
- У нас есть некоторый набор данных уже готовый, мы можем сразу скинуть их в файл и на этом все.
- Данные поступают или формируются постепенно. В этом случае имеет смысл накопить какое-то количество в буфере и потом записать буфер, затем дождаться пока они накопиться вновь и снова записать. И так до полного удовлетворения (пока данные не перестанут поступать).
Скорость записи данных
Вспомним усреднённые значения по скорости записи:
- В HDD - 96 Мбайт/с;
- В SSD - 490 Мбайт/с (современные - до 7000 Мбайт/с);
- В ОЗУ - от 10 000 Мбайт/с.
Т.е. при любом раскладе, скорость записи в буфер обмена больше записи на внутреннее хранилище. Если строк много - для повышения производительности приложения и экономии ресурсов выгоднее использовать запись информации в файл через буфер.
Следует ещё помнить, что экономия ресурсов - субъективная штука, потому что всё зависит от задачи. Допустим, у нас этих строк полтора терабайта: едва ли существует буфер подобного размера. Логичнее писать эти строки в файл частями. Не исключено, что и отдельными строками.
Многое зависит от того, с какими данными мы работаем. И способов записи строк в файл гораздо больше двух, описанных в этой и предыдущей статье.
Объём информации
- 1 КБ = 1 000 байт; другое написание 1 Кбайт;
- 1 МБ = 1 000 КБ = 1 000 000 байт; другое написание 1 Мбайт;
- 1 КиБ = 1 024 байт = 2^10 байт; другое название - килобинарный байт или кибибайт;
- 1 МиБ = 1 024 х 1024 байт = 2^20 байт; другое название - мегабинарный байт или мебибайт;
- 1 Мбит = 1 000 000 бит;
- Мб - некорректный синоним Мбайта или Мбита согласно стандартра ГОСТ 8.417-2002. Однако в стандартах ГОСТ Р МЭК 80000-13—2016, ГОСТ IEC 60027-2-2015, IEEE 1541-2002, IEEE Std 260.1-2004 используется сокращение b для bit. Для однозначности трактовки, следует применять единицы измерения по СИ, т.е. исходя из примеров выше.
-//-//-
Напоминаю, если захотите купить курс от SkillBox, воспользуйтесь моей реферальной ссылкой. Вы получите огромную скидку на курс и плюс в карму за помощь каналу.
PS Сообщите, если купили курс по моей ссылке. Этим ребятам иногда нужно напоминать, что курс куплен по рефу, иначе что-то может пойти не так и кэшбэк не начисляют.
Бро, ты уже здесь? 👉 Подпишись на канал в «Я, Golang-инженер» в Telegram, будем изучать IT вместе 👨💻👩💻👨💻