我可以使用一些帮助来优化一些 Common Lisp 代码。我正在尝试从日志文件中查询数据。从超过 14.5k 行中提取前 50 行需要一秒钟。推断出来,从日志文件中读取数据大约需要 5 分钟。此外,当整个文件只有 14MB 时,我当前实现的前 50 行分配了 ~50MB。我想要这样做的是对数据执行 1 次读取,以使用最少数量的内存分配对其进行解析。
我知道我看到的性能下降是由于我的代码。我很难思考如何重构我的代码以尽量减少我看到的问题。我尝试使用 WITH-INPUT-FROM-STRING 将字符串作为流访问,并且性能没有明显变化。
这是一个 IIS 日志,因此它具有一致的结构。前 2 个字段是日期和时间,我想将其解析为一个数字,以便在需要时限制数据范围。之后,大部分字段的大小都是可变的,但都用空格分隔。
使用我的代码:使用 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)))))
我的第一次尝试是一种非常幼稚的方法,我认识到我的代码现在可以使用一些改进,所以我要求一些方向。如果教程更适合回答此问题,请发布链接。我喜欢