Создать метку времени с долями секунды - PullRequest
0 голосов
/ 26 марта 2019

awk может генерировать метку времени с функцией strftime, например,

$ awk 'BEGIN {print strftime("%Y/%m/%d %H:%M:%S")}'
2019/03/26 08:50:42

Но мне нужна временная метка с долями секунд, в идеале до наносекунд. gnu date может сделать это с элементом %N:

$ date "+%Y/%m/%d %H:%M:%S.%N"
2019/03/26 08:52:32.753019800

Но относительно неэффективно вызывать date из awk по сравнению с вызовом strftime, и мне нужна высокая производительность, так как я обрабатываю много больших файлов с awk и мне нужно генерировать много временных меток при обработке файлы. Есть ли способ, которым awk может эффективно генерировать метку времени, которая включает доли секунды (в идеале, наносекунды, но миллисекунды были бы приемлемы)?

Добавление примера того, что я пытаюсь выполнить:

awk -v logFile="$logFile" -v outputFile="$outputFile" '
BEGIN {
   print "[" strftime("%Y%m%d %H%M%S") "] Starting to process " FILENAME "." >> logFile
}
{
    data[$1] += $2
}
END {
    print "[" strftime("%Y%m%d %H%M%S") "] Processed " NR " records." >> logFile
    for (id in data) {
        print id ": " data[id] >> outputFile
    }
}
' oneOfManyLargeFiles

Ответы [ 2 ]

2 голосов
/ 27 марта 2019

Если вы действительно нуждаетесь в подсекундной синхронизации, то любой вызов внешней команды, такой как date или чтение внешнего системного файла, такого как /proc/uptime или /proc/rct, лишает цели точности до секунды.В обоих случаях требуется много ресурсов для извлечения запрошенной информации (т.е. времени)

Поскольку OP уже использует GNU awk, вы можете использовать динамическое расширение.Динамические расширения - это способ добавления новых функций в awk путем реализации новых функций, написанных на C или C ++, и динамической загрузки их с помощью gawk.Как написать эти функции, подробно описано в руководстве GNU awk .

К счастью, GNU awk 4.2.1 поставляется с набором динамических библиотек по умолчанию, которые можно загружать по желанию.Одна из этих библиотек - это библиотека time с двумя простыми функциями:

the_time = gettimeofday() Возвращает время в секундах, прошедшее с 1970-01-01 UTC, в видезначение с плавающей точкой.Если время недоступно для этой платформы, верните -1 и установите ERRNO. Возвращаемое время должно быть с точностью до секунды , но фактическая точность может варьироваться в зависимости от платформы.Если на этой платформе доступен стандартный системный вызов C gettimeofday(), он просто возвращает значение.В противном случае, если на MS-Windows, он пытается использовать GetSystemTimeAsFileTime().

result = sleep(seconds) Попытка спать в течение seconds секунд.Если seconds отрицательно или попытка заснуть не удалась, верните -1 и установите ERRNO.В противном случае верните ноль после сна в течение указанного количества времени.Обратите внимание, что секунды могут быть значениями с плавающей точкой (нецелыми).Детали реализации: в зависимости от доступности платформы, эта функция пытается использовать nanosleep() или select() для реализации задержки.

источник: GNU awk manual

Теперь можно вызывать эту функцию довольно простым способом:

awk '@load "time"; BEGIN{printf "%.6f", gettimeofday()}'
1553637193.575861

Чтобы продемонстрировать, что этот метод быстрее, чем более классические реализацииЯ рассчитал все 3 реализации, используя gettimeofday():

awk '@load "time"
     function get_uptime(   a) {
        if((getline line < "/proc/uptime") > 0)
        split(line,a," ")
        close("/proc/uptime")
        return a[1]
     }
     function curtime(    cmd, line, time) {
        cmd = "date \047+%Y/%m/%d %H:%M:%S.%N\047"
        if ( (cmd | getline line) > 0 ) {
           time = line
        }
        else {
           print "Error: " cmd " failed" | "cat>&2"
        }
        close(cmd)
        return time
      }
      BEGIN{
        t1=getimeofday(); curtime(); t2=gettimeofday();
        print "curtime()",t2-t1
        t1=getimeofday(); get_uptime(); t2=gettimeofday();
        print "get_uptime()",t2-t1
        t1=getimeofday(); gettimeofday(); t2=gettimeofday();
        print "gettimeofday()",t2-t1
      }'

, который выдает:

curtime() 0.00519109
get_uptime() 7.98702e-05
gettimeofday() 9.53674e-07

Хотя очевидно, что curtime() является самым медленным, поскольку он загружает внешний двоичный файл,довольно удивительно видеть, что awk невероятно быстр в обработке дополнительного внешнего файла / proc /.

1 голос
/ 26 марта 2019

Если вы работаете в Linux, вы можете использовать /proc/uptime:

$ cat /proc/uptime 
123970.49 354146.84

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

$ while true ; do echo ping ; sleep 0.989 ; done |        # yes | awk got confusing
awk '
function get_uptime(   a) {
    if((getline line < "/proc/uptime") > 0)
        split(line,a," ")
    close("/proc/uptime")
    return a[1]
}
BEGIN {
    basetime=get_uptime()                    
}
{
    if(!wut)                                 # define here the cause
        print get_uptime()-basetime          # calculate time difference
}'

Выход:

0
0.99
1.98
2.97
3.97
...