Я написал небольшой пакетный файл для преобразования файла, содержащего восемь 16-битных шестнадцатеричных значений на строку, в файл CSV с восемью значениями в десятичном виде.
Файл входных данных представлял собой записанные выходные данные значений АЦП встроенного устройства, отправленные в пакетах из восьми шестнадцатеричных значений в ASCII с возвратом каретки плюс перевод строки через RS-232 на ПК и просто записанные на ПК в файл. Одна строка во входном файле данных была что-то вроде:
000A002D0044008B0125018C01F40237
CSV-файл для этой строки:
10,45,68,139,293,396,500,567
Пакетный файл работал, но потребовалось несколько минут, чтобы завершить преобразование, которое шокировало меня Я ожидал, что для выполнения этой задачи командный процессор Windows займет несколько секунд, а консольное приложение, написанное на C или C ++, может за несколько миллисекунд. Но время выполнения файла для данных размером менее 512 КиБ в несколько минут определенно не ожидалось.
Итак, я рассмотрел эту проблему далее, создав пакетный файл с использованием четырех различных методов для создания файла CSV с десятичными значениями из файла данных с шестнадцатеричными значениями.
Ниже приведен полный пакетный файл для тестирования четырех методов, а также результаты моих испытаний.
Я понимаю, что первые два метода, использующие подпрограмму, намного медленнее, чем два последних метода, выполняющих преобразование в одном цикле с выводом каждой строки CSV в файл на каждой итерации цикла соответственно один раз в конце FOR цикл из-за вызова подпрограммы вызывает несколько дополнительных шагов, выполняемых cmd.exe
, что в целом отнимает много времени при вызове подпрограммы тысячи раз.
Но я не совсем понимаю, почему первый метод, использующий цикл GOTO , примерно в шесть раз медленнее, чем цикл FOR с почти одинаковыми двумя командными строками.
Код пакетного файла метода 1:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "DelDataFile="
set "DataFile=%TEMP%\HexValues.dat"
if not exist "%DataFile%" set "DelDataFile=1" & echo 000A002D0044008B0125018C01F40237>"%DataFile%"
for /F "usebackq delims=" %%I in ("%DataFile%") do call :ConvertLine "%%I"
if defined DelDataFile del "%DataFile%"
endlocal
goto :EOF
:ConvertLine
set "DataLine=%~1"
set "AllValues="
set "StartColumn=0"
:NextValue
set /A Value=0x!DataLine:~%StartColumn%,4!
set "AllValues=%AllValues%,%Value%"
set /A StartColumn+=4
if not %StartColumn% == 32 goto NextValue
echo %AllValues:~1%
goto :EOF
Код командного файла метода 2:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "DelDataFile="
set "DataFile=%TEMP%\HexValues.dat"
if not exist "%DataFile%" set "DelDataFile=1" & echo 000A002D0044008B0125018C01F40237>"%DataFile%"
for /F "usebackq delims=" %%I in ("%DataFile%") do call :LineConvert "%%I"
if defined DelDataFile del "%DataFile%"
endlocal
goto :EOF
:LineConvert
set "DataLine=%~1"
set "AllValues="
for /L %%J in (0,4,28) do (
set /A Value=0x!DataLine:~%%J,4!
set "AllValues=!AllValues!,!Value!"
)
echo !AllValues:~1!
goto :EOF
И еще я обнаружил во время выполнения тестов, чтобы самостоятельно выяснить причину, по которой метод 1 на ПК, работающем от батареи, длится на 5-10 секунд дольше, чем на подключенном блоке питания.
Вопрос:
В чем причина гораздо более медленного выполнения цикла GOTO , используемого в методе 1, по сравнению с циклом FOR , используемого в методе 2, и почему метод 1 зависит от вида Блок питания ПК?
Вот весь пакетный файл, используемый для сравнения различных методов:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
cls
set "TestRuns=5"
set "DelDataFile="
set "DataFile=%TEMP%\HexValues.dat"
if exist "%DataFile%" goto InitMethod1
set "DelDataFile=1"
echo Creating data file which takes some seconds, please wait ...
setlocal
set "HexDigits=0123456789ABCDEF"
set "DataLine="
(for /L %%I in (0,1,32767) do (
set /A "Digit1=(%%I >> 12) %% 16"
set /A "Digit2=(%%I >> 8) %% 16"
set /A "Digit3=(%%I >> 4) %% 16"
set /A "Digit4=%%I %% 16"
set "HexValue="
for %%J in (!Digit1! !Digit2! !Digit3! !Digit4!) do set "HexValue=!HexValue!!HexDigits:~%%J,1!"
set "DataLine=!DataLine!!HexValue!"
set /A "ValuesPerLine=%%I %% 8"
if !ValuesPerLine! == 7 (
echo !DataLine!
set "DataLine="
)
))>"%DataFile%"
endlocal
echo/
:InitMethod1
call :MethodInit 1
:RunMethod1
set /A TestRun+=1
set "CSV_File=%TEMP%\Values%Method%_%TestRun%.csv"
del "%CSV_File%" 2>nul
call :GetTime StartTime
for /F "usebackq delims=" %%I in ("%DataFile%") do call :ConvertLine "%%I"
call :OutputTime
if %TestRun% LSS %TestRuns% goto RunMethod1
call :MethodResults
goto InitMethod2
:ConvertLine
set "DataLine=%~1"
set "AllValues="
set "StartColumn=0"
:NextValue
set /A Value=0x!DataLine:~%StartColumn%,4!
set "AllValues=%AllValues%,%Value%"
set /A StartColumn+=4
if not %StartColumn% == 32 goto NextValue
>>"%CSV_File%" echo %AllValues:~1%
goto :EOF
:InitMethod2
call :MethodInit 2
:RunMethod2
set /A TestRun+=1
set "CSV_File=%TEMP%\Values%Method%_%TestRun%.csv"
del "%CSV_File%" 2>nul
call :GetTime StartTime
for /F "usebackq delims=" %%I in ("%DataFile%") do call :LineConvert "%%I"
call :OutputTime
if %TestRun% LSS %TestRuns% goto RunMethod2
call :MethodResults
goto InitMethod3
:LineConvert
set "DataLine=%~1"
set "AllValues="
for /L %%J in (0,4,28) do (
set /A Value=0x!DataLine:~%%J,4!
set "AllValues=!AllValues!,!Value!"
)
echo !AllValues:~1!>>"%CSV_File%"
goto :EOF
:InitMethod3
call :MethodInit 3
:RunMethod3
set /A TestRun+=1
set "CSV_File=%TEMP%\Values%Method%_%TestRun%.csv"
del "%CSV_File%" 2>nul
call :GetTime StartTime
for /F "usebackq delims=" %%I in ("%DataFile%") do (
set "DataLine=%%I"
set "AllValues="
for /L %%J in (0,4,28) do (
set /A Value=0x!DataLine:~%%J,4!
set "AllValues=!AllValues!,!Value!"
)
echo !AllValues:~1!>>"%CSV_File%"
)
call :OutputTime
if %TestRun% LSS %TestRuns% goto RunMethod3
call :MethodResults
goto InitMethod4
:InitMethod4
call :MethodInit 4
:RunMethod4
set /A TestRun+=1
set "CSV_File=%TEMP%\Values%Method%_%TestRun%.csv"
del "%CSV_File%" 2>nul
call :GetTime StartTime
(for /F "usebackq delims=" %%I in ("%DataFile%") do (
set "DataLine=%%I"
set "AllValues="
for /L %%J in (0,4,28) do (
set /A Value=0x!DataLine:~%%J,4!
set "AllValues=!AllValues!,!Value!"
)
echo !AllValues:~1!
))>>"%CSV_File%"
call :OutputTime
if %TestRun% LSS %TestRuns% goto RunMethod4
call :MethodResults
goto EndBatch
:GetTime
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "%1=%%I"
goto :EOF
:MethodInit
set "Method=%1"
echo Test runs with method %Method%
echo -----------------------
echo/
set "TestRun=0"
set "TotalTime=0"
goto :EOF
:MethodResults
set /A AverageTime=TotalTime / TestRun
echo Method %Method% total time: %TotalTime% seconds
echo Method %Method% average time: %AverageTime% seconds
echo/
goto :EOF
:OutputTime
call :GetTime EndTime
set /A StartTime=(1%StartTime:~8,2% - 100) * 3600 + (1%StartTime:~10,2% - 100) * 60 + 1%StartTime:~12,2% - 100
set /A EndTime=(1%EndTime:~8,2% - 100) * 3600 + (1%EndTime:~10,2% - 100) * 60 + 1%EndTime:~12,2% - 100
set /A DiffTime=EndTime - StartTime
set /A TotalTime+=DiffTime
echo Method %Method% run %TestRun% time: %DiffTime% seconds
goto :EOF
:EndBatch
if defined DelDataFile del "%DataFile%"
del /Q "%TEMP%\Values?_*.csv"
endlocal
Сначала создается файл данных с увеличивающимися шестнадцатеричными значениями в папке для временных файлов, которые занимают уже несколько секунд. Пожалуйста, прокомментируйте предпоследнюю командную строку этого пакетного файла, чтобы сохранить этот файл в случае многократного запуска этого пакетного файла или интереса к этому файлу.
Затем он запускает пять раз четыре метода для чтения шестнадцатеричных значений из файла данных и записи значений в десятичном виде в файл CSV с печатью результатов теста на консоль, соответственно обработать STDOUT .
Наконец, он удаляет все файлы CSV, созданные также в папке для временных файлов, имеющих одинаковое содержимое. Пожалуйста, прокомментируйте последнюю, но одну командную строку, чтобы эти CSV-файлы интересовались этими файлами.
Этот пакетный файл был выполнен мной четыре раза на двух ноутбуках.
Ниже приведены результаты первого запуска на ноутбуке с процессором Intel Core Duo P8400 с тактовой частотой 2,26 ГГц и 2 ГБ ОЗУ с жестким диском с частотой вращения 7200 об / мин под управлением Windows XP x86 с подключенным источником питания:
Test runs with method 1
-----------------------
Method 1 run 1 time: 51 seconds
Method 1 run 2 time: 51 seconds
Method 1 run 3 time: 51 seconds
Method 1 run 4 time: 52 seconds
Method 1 run 5 time: 51 seconds
Method 1 total time: 256 seconds
Method 1 average time: 51 seconds
Test runs with method 2
-----------------------
Method 2 run 1 time: 9 seconds
Method 2 run 2 time: 9 seconds
Method 2 run 3 time: 9 seconds
Method 2 run 4 time: 8 seconds
Method 2 run 5 time: 9 seconds
Method 2 total time: 44 seconds
Method 2 average time: 9 seconds
Test runs with method 3
-----------------------
Method 3 run 1 time: 3 seconds
Method 3 run 2 time: 3 seconds
Method 3 run 3 time: 4 seconds
Method 3 run 4 time: 3 seconds
Method 3 run 5 time: 3 seconds
Method 3 total time: 16 seconds
Method 3 average time: 3 seconds
Test runs with method 4
-----------------------
Method 4 run 1 time: 3 seconds
Method 4 run 2 time: 2 seconds
Method 4 run 3 time: 2 seconds
Method 4 run 4 time: 2 seconds
Method 4 run 5 time: 2 seconds
Method 4 total time: 11 seconds
Method 4 average time: 2 seconds
Метод 2 в 5,67 раза быстрее, чем метод 1. Методы 3 и 4 даже быстрее, чем метод 2, но я ожидаю этого. Большинство 2 и 3 секунд, необходимых для методов 3 и 4, относятся к команде WMIC для получения локальной даты и времени в формате, не зависящем от региона.
Вот результаты второго запуска на том же компьютере, что и первый запуск, с разницей при запуске компьютера на полностью заряженной батарее:
Test runs with method 1
-----------------------
Method 1 run 1 time: 63 seconds
Method 1 run 2 time: 61 seconds
Method 1 run 3 time: 61 seconds
Method 1 run 4 time: 61 seconds
Method 1 run 5 time: 61 seconds
Method 1 total time: 307 seconds
Method 1 average time: 61 seconds
Test runs with method 2
-----------------------
Method 2 run 1 time: 11 seconds
Method 2 run 2 time: 10 seconds
Method 2 run 3 time: 10 seconds
Method 2 run 4 time: 10 seconds
Method 2 run 5 time: 10 seconds
Method 2 total time: 51 seconds
Method 2 average time: 10 seconds
Test runs with method 3
-----------------------
Method 3 run 1 time: 3 seconds
Method 3 run 2 time: 4 seconds
Method 3 run 3 time: 3 seconds
Method 3 run 4 time: 4 seconds
Method 3 run 5 time: 3 seconds
Method 3 total time: 17 seconds
Method 3 average time: 3 seconds
Test runs with method 4
-----------------------
Method 4 run 1 time: 2 seconds
Method 4 run 2 time: 2 seconds
Method 4 run 3 time: 2 seconds
Method 4 run 4 time: 2 seconds
Method 4 run 5 time: 2 seconds
Method 4 total time: 10 seconds
Method 4 average time: 2 seconds
Видно, что для методов со 2 по 4 время обработки увеличивается немного.Но время обработки метода 1 увеличивается на 10 секунд, и поэтому это решение теперь примерно в 6,10 раз медленнее, чем у метода 2. Я понятия не имею, почему время обработки метода 1 зависит от типа источника питания.
ВотРезультаты первого запуска на ноутбуке с Intel Core Duo T9600 с тактовой частотой 2,80 ГГц и 4 ГБ ОЗУ с SSD под управлением Windows 7 x64 с подключенным источником питания:
Test runs with method 1
-----------------------
Method 1 run 1 time: 91 seconds
Method 1 run 2 time: 88 seconds
Method 1 run 3 time: 77 seconds
Method 1 run 4 time: 77 seconds
Method 1 run 5 time: 78 seconds
Method 1 total time: 411 seconds
Method 1 average time: 82 seconds
Test runs with method 2
-----------------------
Method 2 run 1 time: 11 seconds
Method 2 run 2 time: 16 seconds
Method 2 run 3 time: 16 seconds
Method 2 run 4 time: 14 seconds
Method 2 run 5 time: 16 seconds
Method 2 total time: 73 seconds
Method 2 average time: 14 seconds
Test runs with method 3
-----------------------
Method 3 run 1 time: 6 seconds
Method 3 run 2 time: 4 seconds
Method 3 run 3 time: 4 seconds
Method 3 run 4 time: 4 seconds
Method 3 run 5 time: 6 seconds
Method 3 total time: 24 seconds
Method 3 average time: 4 seconds
Test runs with method 4
-----------------------
Method 4 run 1 time: 4 seconds
Method 4 run 2 time: 3 seconds
Method 4 run 3 time: 5 seconds
Method 4 run 4 time: 4 seconds
Method 4 run 5 time: 4 seconds
Method 4 total time: 20 seconds
Method 4 average time: 4 seconds
Интересно было увидеть, что пакетВыполнение файлов с более мощным оборудованием занимает больше времени в Windows 7 x64, чем в Windows XP x86.Но еще более интересным для меня является тот факт, что метод 2 в 5,86 раза быстрее, чем метод 1, только благодаря использованию FOR вместо цикла GOTO .
Для полноты результатов четвертого прогона на том же компьютере, что и третий прогон, с разницей при запуске ПК на полностью заряженном аккумуляторе:
Test runs with method 1
-----------------------
Method 1 run 1 time: 97 seconds
Method 1 run 2 time: 91 seconds
Method 1 run 3 time: 90 seconds
Method 1 run 4 time: 81 seconds
Method 1 run 5 time: 77 seconds
Method 1 total time: 436 seconds
Method 1 average time: 87 seconds
Test runs with method 2
-----------------------
Method 2 run 1 time: 12 seconds
Method 2 run 2 time: 16 seconds
Method 2 run 3 time: 17 seconds
Method 2 run 4 time: 16 seconds
Method 2 run 5 time: 13 seconds
Method 2 total time: 74 seconds
Method 2 average time: 14 seconds
Test runs with method 3
-----------------------
Method 3 run 1 time: 6 seconds
Method 3 run 2 time: 6 seconds
Method 3 run 3 time: 5 seconds
Method 3 run 4 time: 5 seconds
Method 3 run 5 time: 5 seconds
Method 3 total time: 27 seconds
Method 3 average time: 5 seconds
Test runs with method 4
-----------------------
Method 4 run 1 time: 4 seconds
Method 4 run 2 time: 4 seconds
Method 4 run 3 time: 5 seconds
Method 4 run 4 time: 4 seconds
Method 4 run 5 time: 4 seconds
Method 4 total time: 21 seconds
Method 4 average time: 4 seconds
Опять же, нет разницы во времени выполнения для методов с 3 по 4 вСравнение с третьим прогоном с подключенным источником питания. Но время выполнения метода 1 увеличивается примерно на 5 секунд, и по этой причине метод 1 в 6,21 раза медленнее, чем метод 2.
Мне было бы действительно интересно, почему метод1 намного медленнее, чем метод 2, и, кроме того, зависит от типа источника питания.
Индикатор активности жесткого диска очень редко мигал во всех тестовых прогонах, как я ожидал, из-за кэширования файлов Windows.