【发布时间】:2019-10-18 15:19:33
【问题描述】:
我有大约 900000 条记录:
(defparameter RECORDS
'((293847 "john menk" "john.menk@example.com" 0123456789 2300 2760 "CHEQUE" 012345 "menk freeway" "high rose")
(244841 "january agami" "j.a@example.com" 0123456789 2300 2760 "CHEQUE" 012345 "ishikawa street" "fremont apartments")
...))
(这些是从文件中读取的。上面的代码仅作为示例提供。它有助于显示这些数据的内部结构。)
为了快速制作原型,我为选择器使用别名:
(defmacro alias (new-name existing-name)
"Alias NEW-NAME to EXISTING-NAME. EXISTING-NAME has to be a function."
`(setf (fdefinition ',new-name) #',existing-name))
(progn
(alias account-number first)
(alias full-name second)
(alias email third)
(alias mobile fourth)
(alias average-paid fifth)
(alias highest-paid sixth)
(alias usual-payment-mode seventh)
(alias pincode eighth)
(alias road ninth)
(alias building tenth))
现在我运行:
(time (loop for field in '(full-name email)
append (loop for record in RECORDS
when (cl-ppcre:scan ".*?january.*?agami.*?"
(funcall (symbol-function field) record))
collect record)))
repl 输出:
...
took 1,714 milliseconds (1.714 seconds) to run.
During that period, and with 4 available CPU cores,
1,698 milliseconds (1.698 seconds) were spent in user mode
9 milliseconds (0.009 seconds) were spent in system mode
40 bytes of memory allocated.
...
定义一个做同样事情的函数:
(defun searchx (regex &rest fields)
(loop for field in fields
append (loop for record in RECORDS
when (cl-ppcre:scan regex (funcall (symbol-function field) record))
collect record)))
然后调用它:
(time (searchx ".*?january.*?agami.*?" 'full-name 'email))
输出:
...
took 123,389 milliseconds (123.389 seconds) to run.
992 milliseconds ( 0.992 seconds, 0.80%) of which was spent in GC.
During that period, and with 4 available CPU cores,
118,732 milliseconds (118.732 seconds) were spent in user mode
4,569 milliseconds ( 4.569 seconds) were spent in system mode
2,970,867,648 bytes of memory allocated.
501 minor page faults, 0 major page faults, 0 swaps.
...
几乎慢了 70 倍?!!
我认为这可能是特定于计算机的问题。所以我在两台不同的机器上运行了相同的代码。一台 macbook air 和一台 macbook pro。个人时间不同,但行为是一致的。将它作为函数调用比直接在两台机器上调用它花费的时间要长得多。当然,单个函数调用的开销应该不会那么慢。
然后我认为可能是 Clozure CL 负责。所以我在 SBCL 中运行了相同的代码,即使在那里行为也很相似。差别不是很大,但还是很大的。它大约慢了 22 倍。
直接运行时SBCL输出:
Evaluation took:
1.519 seconds of real time
1.477893 seconds of total run time (0.996071 user, 0.481822 system)
97.30% CPU
12 lambdas converted
2,583,290,520 processor cycles
492,536 bytes consed
作为函数运行时的SBCL输出:
Evaluation took:
33.522 seconds of real time
33.472137 seconds of total run time (33.145166 user, 0.326971 system)
[ Run times consist of 0.254 seconds GC time, and 33.219 seconds non-GC time. ]
99.85% CPU
56,989,918,442 processor cycles
2,999,581,336 bytes consed
为什么将代码作为函数调用这么慢?我该如何解决?
【问题讨论】:
标签: regex performance common-lisp