在我的项目中,我需要处理很多坐标,在2D情况下,我发现(cons x y)
的构造比(list x y)
和(vector x y)
快。
但是,我不知道如何将cons
扩展到3D或更远,因为我找不到像cons3
这样的内容。在common-lisp中有快速tuple
的解决方案吗?
为了说明,我做了以下测试:
* (time (loop repeat 10000 do (loop repeat 10000 collect (cons (random 10) (random 10)))))
Evaluation took:
7.729 seconds of real time
7.576000 seconds of total run time (7.564000 user, 0.012000 system)
[ Run times consist of 0.068 seconds GC time, and 7.508 seconds non-GC time. ]
98.02% CPU
22,671,859,477 processor cycles
3,200,156,768 bytes consed
NIL
* (time (loop repeat 10000 do (loop repeat 10000 collect (list (random 10) (random 10)))))
Evaluation took:
8.308 seconds of real time
8.096000 seconds of total run time (8.048000 user, 0.048000 system)
[ Run times consist of 0.212 seconds GC time, and 7.884 seconds non-GC time. ]
97.45% CPU
24,372,206,280 processor cycles
4,800,161,712 bytes consed
NIL
* (time (loop repeat 10000 do (loop repeat 10000 collect (vector (random 10) (random 10)))))
Evaluation took:
8.460 seconds of real time
8.172000 seconds of total run time (8.096000 user, 0.076000 system)
[ Run times consist of 0.260 seconds GC time, and 7.912 seconds non-GC time. ]
96.60% CPU
24,815,721,033 processor cycles
4,800,156,944 bytes consed
NIL
答案 0 :(得分:3)
这种数据结构的一般方法是使用defstruct
。这是您在Common Lisp中创建数据结构的方法。所以,如果你想在三维空间中有一个点,这或多或少都是你要做的:
(defstruct point-3d x y z)
为什么这比阵列更好:
正确命名。
它创建了一堆你正在创建的有用的东西,比如访问器,测试某些数据是否属于这种类型的函数,构造这种类型的对象的函数以及其他一些好东西。
然后在数组中打字更精细:您可以分别指定每个插槽的类型。
专业打印功能,可以很好地打印您的数据。
为什么这比列表更好:
(defstruct (point-3d (:type list)) x y z)
您应该尝试探索其他替代方案。创建数组或等效内存印记的缺点单元之间的区别不值得优化。如果您遇到此特定操作的问题,则应该认为该任务通常无法管理。但我真的认为应首先尝试对象池,memoization和一般缓存等技术。
另一个要点:您没有告诉编译器尝试生成有效的代码。您可以告诉编译器优化大小,速度或调试。在指定要尝试提取的优化类型后,您应该真正衡量性能。
我写了一个快速测试,看看有什么区别:
(defstruct point-3d
(x 0 :type fixnum)
(y 0 :type fixnum)
(z 0 :type fixnum))
(defun test-struct ()
(declare (optimize speed))
(loop :repeat 1000000 :do
(make-point-3d :x (random 10) :y (random 10) :y (random 10))))
(time (test-struct))
;; Evaluation took:
;; 0.061 seconds of real time
;; 0.060000 seconds of total run time (0.060000 user, 0.000000 system)
;; 98.36% CPU
;; 133,042,429 processor cycles
;; 47,988,448 bytes consed
(defun test-array ()
(declare (optimize speed))
(loop :repeat 1000000
:for point :of-type (simple-array fixnum (3)) :=
(make-array 3 :element-type 'fixnum) :do
(setf (aref point 0) (random 10)
(aref point 1) (random 10)
(aref point 2) (random 10))))
(time (test-array))
;; Evaluation took:
;; 0.048 seconds of real time
;; 0.047000 seconds of total run time (0.046000 user, 0.001000 system)
;; 97.92% CPU
;; 104,386,166 processor cycles
;; 48,018,992 bytes consed
我的测试的第一个版本出现了偏差,因为我在第一次测试之前忘了运行GC,因此在上一次测试之后不得不回收内存而使其处于不利地位。现在数字更精确,并且还表明使用结构和数组几乎没有区别。
所以,再次,按照我之前的建议:使用对象池,memoization,或者你可能想到的任何其他优化技术。优化这里是一个死胡同。
答案 1 :(得分:2)
使用声明和内联函数,结构可能比数组和列表都快:
(declaim (optimize (speed 3) (safety 0) (space 3)))
(print "Testing lists");
(terpri)
(time (loop repeat 10000 do
(loop repeat 10000
collect (list (random 1000.0)
(random 1000.0)
(random 1000.0)))))
(print "Testing arrays");
(terpri)
(declaim (inline make-pnt))
(defun make-pnt (&rest coords)
(make-array 3 :element-type 'single-float :initial-contents coords))
(time (loop repeat 10000 do
(loop repeat 10000
collect (make-pnt (random 1000.0)
(random 1000.0)
(random 1000.0)))))
(print "Testing structs")
(terpri)
(declaim (inline new-point))
(defstruct (point
(:type (vector single-float))
(:constructor new-point (x y z)))
(x 0.0 :type single-float)
(y 0.0 :type single-float)
(z 0.0 :type single-float))
(time (loop repeat 10000 do
(loop repeat 10000
collect (new-point (random 1000.0)
(random 1000.0)
(random 1000.0)))))
"Testing lists"
Evaluation took:
8.940 seconds of real time
8.924558 seconds of total run time (8.588537 user, 0.336021 system)
[ Run times consist of 1.109 seconds GC time, and 7.816 seconds non-GC time. ]
99.83% CPU
23,841,394,328 processor cycles
6,400,180,640 bytes consed
"Testing arrays"
Evaluation took:
8.154 seconds of real time
8.140509 seconds of total run time (7.948497 user, 0.192012 system)
[ Run times consist of 0.724 seconds GC time, and 7.417 seconds non-GC time. ]
99.84% CPU
21,743,874,280 processor cycles
4,800,178,240 bytes consed
"Testing structs"
Evaluation took:
7.631 seconds of real time
7.620476 seconds of total run time (7.432464 user, 0.188012 system)
[ Run times consist of 0.820 seconds GC time, and 6.801 seconds non-GC time. ]
99.86% CPU
20,350,103,048 processor cycles
4,800,179,360 bytes consed
答案 2 :(得分:1)
我假设你正在使用浮点值,在这种情况下(make-array 3 :element-type 'single-float)
可能是最好的。这样,您可以期望浮动存储为未装箱(在大多数实现中)。
请务必随身携带(declare (type (simple-array single-float (3))))
。