optimization - 通用 Lisp : Optimizing file parsing for minimum reads and memory allocations

标签 optimization common-lisp

我需要一些帮助来优化一些 Common Lisp 代码。我正在尝试从日志文件中查询数据。从超过 14.5k 行中拉出前 50 行需要花费一秒钟的时间。由此推断,仅从日志文件中读取数据就需要将近 5 分钟。此外,当整个文件只有 14MB 时,我当前实现的前 50 行分配了约 50MB。我想要做的是执行 1 次读取数据,以使用最少数量的内存分配来解析它。

我知道我所看到的性能下降是由于我的代码造成的。我很难思考如何重构我的代码以最大程度地减少我所看到的问题。我尝试使用WITH-INPUT-FROM-STRING 将字符串作为流访问,并且性能没有明显变化。

这是一个 IIS 日志,因此它将具有一致的结构。前两个字段是日期和时间,我想将其解析为数字,以便在需要时限制数据范围。之后,大多数字段的大小将是可变的,但所有字段均以空格分隔。

使用我的代码:使用 8 个可用 CPU 内核运行需要 1,138,000 微秒(1.138000 秒)。 在此期间,用户模式花费了 1,138,807 微秒(1.138807 秒) 在系统模式下花费了 0 微秒(0.000000 秒) GC 花费了 19,004 微秒(0.019004 秒)。 已分配 49,249,040 字节内存。

没有我的代码:使用 8 个可用 CPU 核心运行需要 64,000 微秒(0.064000 秒)。 在此期间,用户模式花费了 62,401 微秒(0.062401 秒) 在系统模式下花费了 0 微秒(0.000000 秒) 已分配 834,512 字节内存。

(defun read-date-time (hit)
  (let ((date-time (chronicity:parse (subseq hit 0 20))))
    (encode-universal-time (chronicity:sec-of date-time)
               (chronicity:minute-of date-time)
               (chronicity:hour-of date-time)
               (chronicity:day-of date-time)
               (chronicity:month-of date-time)
               (chronicity:year-of date-time))))

(defun parse-hit (hit)
  (unless (eq hit :eof)
    (cons (read-date-time hit)
          (split-sequence:split-sequence #\Space (subseq hit 20)))))


(time (gzip-stream:with-open-gzip-file (ins "C:\\temp\\test.log.gz") 
  (read-line ins nil :eof)
  (loop for i upto 50 
     do (parse-hit (read-line ins nil :eof)))))

我的第一次尝试是一种非常幼稚的方法,我认识到我的代码现在可以进行一些改进,所以我要求一些指导。如果教程更适合回答这个问题,请发布一个链接。我喜欢

最佳答案

问题在于 Chronicity 包,它在内部使用了 Local Time 包。

这个:

   (encode-universal-time (chronicity:sec-of date-time)
           (chronicity:minute-of date-time)
           (chronicity:hour-of date-time)
           (chronicity:day-of date-time)
           (chronicity:month-of date-time)
           (chronicity:year-of date-time))))

压垮你了。

chronicity:month-of 调用 local-time:timestamp-month。如果你看一下代码:

 (nth-value 1
         (%timestamp-decode-date
          (nth-value 1 (%adjust-to-timezone timestamp timezone))))

所以,这里是对基本日期(看起来是一个整数)进行两次解码(一次是时区,另一次是月份。

因此,您要对同一日期进行解码,执行相同的工作,每个日期执行 6 次。这些惯例正在引发一场 Storm 。

您还调用了两次 subseq。

所以,在我看来,在这种情况下你需要专注于日期解析逻辑,使用不太通用的东西。您不必验证日期(假定日志是准确的),也不需要转换为自纪元以来的天/秒/毫秒,您只需要单独的 MDY、HMS 数据。您将使用当前的软件包完成所有这些工作,一旦创建了通用时间,这些工作就变得多余了。

您也可能不关心时区。

无论如何,这就是问题所在的开始。这还不是 I/O 问题。

关于optimization - 通用 Lisp : Optimizing file parsing for minimum reads and memory allocations,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19471170/

相关文章:

php - 从一个表中动态获取行并从其他表中获取值,将其求和并插入到目标表中

c - 为什么我的并行代码比顺序代码慢?

recursion - LISP 迭代到递归

function - 抑制 LISP 中未使用的函数参数的警告

optimization - 当字符串超过 7 个字节时,字符串的 Redis int 表示更大,否则更小

c - 我需要对此函数进行哪些更改来优化执行时间?

javascript - 针对移动/低速连接进行优化 - 全背景视频

recursion - 从 Lisp 中的列表中删除子列表

lisp - delete-if 中谓词的多个参数

amazon-web-services - 部署 Common Lisp Web 应用程序