我需要一些帮助来优化一些 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/