common-lisp 中有“元组”等价的东西吗?

Sal*_*Egg 3 tuples common-lisp

在我的项目中,我有很多坐标需要处理,在 2D 情况下,我发现 的构建比和(cons x y)更快。(list x y)(vector x y)

但是,我不知道如何扩展cons到 3D 或更进一步,因为我没有找到类似cons3. tuplecommon-lisp 中有快速的解决方案吗?

为了便于说明,我做了以下测试:

* (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
Run Code Online (Sandbox Code Playgroud)

小智 6

处理此类数据结构的一般方法是使用defstruct. 这就是在 Common Lisp 中创建数据结构的方式。所以,如果你想在三维空间中有一个点,你或多或少会这样做:

(defstruct point-3d x y z)
Run Code Online (Sandbox Code Playgroud)

为什么这比数组更好:

  1. 它正确地命名了事物。

  2. 它创建了一堆你无论如何都会创建的有用的东西,例如访问器、测试某些数据是否属于这种类型的函数、构造这种类型的对象的函数以及其他一些好东西。

  3. 键入比数组更复杂:您可以单独指定每个槽的类型。

  4. 专业的打印功能,可以很好地打印您的数据。

为什么这比列出的更好:

  1. 您始终可以通过执行以下操作来要求结构充当列表:

(defstruct (point-3d (:type list)) x y z)
Run Code Online (Sandbox Code Playgroud)
  • 和数组都是一样的东西。

优化问题:

您可能应该尝试探索其他替代方案。创建具有等效内存印记的数组或 cons 单元之间的差异不值得对其进行优化。如果您遇到此特定操作的问题,您应该认为该任务通常难以管理。但我确实认为应该首先尝试对象池、记忆化和通用缓存等技术。

另一个要点:您没有告诉编译器尝试生成有效的代码。您可以告诉编译器优化大小、速度或调试。在指定要尝试进行哪种优化之后,您应该真正测量性能。


我写了一个快速测试来看看有什么区别:

(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
Run Code Online (Sandbox Code Playgroud)

我的测试的第一个版本出现了偏差,因为我忘记在第一个测试之前运行 GC,因此由于必须回收上一个测试后留下的内存而处于不利地位。现在数字更加精确,并且还表明使用结构体和数组实际上没有区别。

因此,再次按照我之前的建议:使用对象池、记忆化以及您可能想到的任何其他优化技术。在这里优化是死胡同。

  • @SaltyEgg,这取决于实现、结构在内存中的表示方式,但数组和结构很可能是同一件事。最终,如果您提供类型信息并且编译器能够找到更紧凑的布局,则结构可能会更有效。无论如何,如果您在创建数组与创建结构体级别遇到问题,您的代码将无法成功。但我的直觉告诉我,你应该优化其他东西才能让它发挥作用。 (2认同)