Intereting Posts
регулярное выражение egrep для раз в пять минут Периодически зависает Показать старые или более старые элементы истории с помощью команды history в zsh Мой texinfo не указан в информации Как изменить тип сервиса хорошо определенных портов в SElinux (centOS 6.5) Не удается установить новое ядро ​​на сервере ubuntu. «Ошибка gzip: stdout: Отсутствие пробела на устройстве», несмотря на обилие дискового пространства Как создать непостоянную виртуальную машину? Как выбрать первое слово в каждой строке и приписать его массиву в скрипте bash для цикла, чтобы получить более одного аргумента Хром не отображает веб-страницу (рука) Заставьте systemd-timesyncd не слушать IPv6 Почему ошибка загрузки ядра отсутствует? Преимущества использования конфигурационных файлов для распространения по общим сценариям запуска? Bash: Как читать по одной строке за один раз из вывода команды? OS X SSH продолжает запрашивать пароль

Процессор является бесплатным, но скрипт bash не использует все ресурсы ЦП

Я запустил простой скрипт для создания большого (10000000 строк) csv-файла с 6 полями, в которых некоторые поля изменялись в каждой строке / строке, используя цикл while. У машины были все (32) процессоры бесплатно, большое количество ОЗУ (~ 31 Гб) было бесплатным.

Я приурочил сценарий к команде

/ usr / bin / time -v bash script.01.sh

После пробега около 2 часов, я получил следующую статистику:

Команда приурочена: «bash script.01.sh»
Время пользователя (в секундах): 1195,14
Системное время (в секундах): 819,71
Процент CPU, полученный этой работой: 27%
Время простоя (настенные часы) (h: mm: ss или m: ss): 2:01:10
Средний общий размер текста (кбайт): 0
Средний размер данных без сортировки (кбайт): 0
Средний размер стека (кбайт): 0
Средний общий размер (кбайт): 0
Максимальный размер резидентного набора (кбайт): 4976
Средний размер резидентного набора (кбайт): 0
Основные ошибки (требующие ввода / вывода): 0
Незначительные (исправление кадра) ошибки страницы: 3131983488
Коммутаторы добровольного контекста: 22593141
Неисключительные переключатели контекста: 10923348
Свопы: 0
Входы файловой системы: 0
Выходы файловой системы: 2182920
Сообщения сокета отправлены: 0
Получены сообщения сокета: 0
Полученные сигналы: 0
Размер страницы (байты): 4096
Статус выхода: 0

Я хочу знать, почему мой скрипт использовал только 27% процессора? Диск IO не был вообще ничем (видел в vmstat output). Так что же вызвало ограничение? Код в скрипте?

Вот сценарий:

#!/usr/bin/env bash number=1 while [[ $number -lt 10000001 ]] ; do fname="FirstName LastName $" lname="" email="fname.lname.$number@domain.com" password="1234567890" altemail="lname.fname.$number@domain.com" mobile="9876543210" echo "$fname,$lname,$email,$password,$altemail,$mobile" >> /opt/list.csv number=$(expr $number + 1) done 

Используя strace , я увидел, что линия

 number=$(expr $number + 1) 

вызывает fork, поиск путей и exec expr . (Я использую bash 4.2.45 на Ubuntu). Эта нехватка файловой системы, диска и процесса привела к тому, что bash получала только около 28% процессора.

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

 ((number = number + 1)) 

bash использовал около 98% процессора, а скрипт работал через полчаса. Это было на однопроцессорном процессоре Celeron с тактовой частотой 1,5 ГГц.

Скрипт как есть, не делает ничего, что работает параллельно, поэтому наличие 32 бесплатных процессоров не поможет. Тем не менее, вы можете распараллелить его, например, разбив его на 10 циклов с 1 миллионом, которые работают параллельно, записывая 10 разных файлов, а затем используя cat для их объединения.

Следующая примерная программа была добавлена ​​@ Arthur2e5:

 max=1000000 step=40000 tmp="$(mktemp -d)" # Spawning. For loops make a bit more sense in a init-test-incr pattern. for ((l = 0; l < max; l += step)); do ( for ((n = l + 1, end = (step + l > max ? max : step + l); n <= end; n++)); do # Putting all those things into the `buf` line gives you a 1.8x speedup. fname="FirstName LastName \$" lname="" email="fname.lname.$n@domain.com" password="1234567890" altemail="lname.fname.$n@domain.com" mobile="9876543210" buf+="$fname,$lname,$email,$password,$altemail,$mobile"$'\n' done printf '%s\n' "$buf" > "$tmp/$l" ) & done # spawning.. wait # Merging. The filename order from globbing will be a mess, # since we didn't format $l to some 0-prefixed numbers. # Let's just do the loop again. for ((l = 0; l < max; l += step)); do printf '%s\n' "$(<"$tmp/$l")" >> /opt/list.csv done # merging.. rm -rf -- "$tmp" # cleanup