我正在写一些代码来生成和处理大量的视频数据。起初我只打算用随机的数据进行工作。
我的技术是治疗的像素作为地图上的R,G,B,A的整数值的,以治疗视频作为这些像素图的矢量的帧,并且在时间上处理视频作为像素映射的这些矢量的矢量。我已经写了三个函数做到这一点可靠,但我遇到了性能问题,他们缩放时。
(defn generateFrameOfRandomVideoData
"Generates a frame of video data which is a vector of maps of pixel values."
[num-pixels-in-frame]
(loop [num-pixels-in-frame num-pixels-in-frame
pixels-added 0
frame '[]]
(if (> num-pixels-in-frame pixels-added)
(recur num-pixels-in-frame
(inc pixels-added)
(conj frame (assoc '{}
:r (rand-int 256)
:g (rand-int 256)
:b (rand-int 256)
:a (rand-int 256))))
frame)))
(defn generateRandomVideoData
"Generates a vector of frames of video data."
[number-of-frames frame-height frame-width]
(loop [number-of-frames number-of-frames
frame-height frame-height
frame-width frame-width
frames '[]]
(if (> number-of-frames (count frames))
(recur number-of-frames
frame-height
frame-width
(conj frames (generateFrameOfRandomVideoData (* frame-height frame-width))))
frames)))
(defn generateRandomizedVideo
"Generates video data based on the specified parameters."
[number-of-frames frame-height frame-width]
(assoc '{}
:number-of-frames number-of-frames
:frame-height frame-height
:frame-width frame-width
:frames (generateRandomVideoData number-of-frames frame-height frame-width)))
调用此使用函数产生1920x1080像素的视频60帧:
(generateRandomizedVideo 60 1920 1080)
当我运行这个调用产生10帧值得1920x1080像素的视频算法很快完成。当我把它制作视频的60帧它停滞不前,无法完成,并产生大量内存。我看着它占用的内存16GB的价值。
这并不真正使任何意义,我。我的算法是O(帧*(帧的帧*宽度)的高度的数量)。帧的数量是O(n)和帧*(高度帧的宽度将在O常数(高度×宽)。这些参数解析为O(n)中。
现在,我已经说服自己,希望你,我的算法是不只是顽固,我觉得我有一些连贯的问题:
谢谢!
多少内存Clojure中的一个整数占用的位?
16个字节,根据clj-memory-meter:
(mem/measure (rand-int 256))
=> "16 B"
只有4个字节被用于表示一个32位的整数的值,但在一个的Clojure是java.lang.Integer
中的相同Java和有额外的存储空间“开销”每java.lang.Object
:
(type (rand-int 256))
=> java.lang.Integer
什么样的开销也储运整数势必映射键原因在哪里?它是在记忆不仅仅是让他们在一个载体而言更昂贵?
是的,几乎两倍在这种情况下:
(mem/measure [(rand-int 256) (rand-int 256) (rand-int 256) (rand-int 256)])
=> "320 B"
(mem/measure {:r (rand-int 256)
:g (rand-int 256)
:b (rand-int 256)
:a (rand-int 256)})
=> "544 B"
每一帧将是相当大的:
(mem/measure
(into [] (repeatedly (* 1920 1080)
(fn [] {:r (rand-int 256)
:g (rand-int 256)
:b (rand-int 256)
:a (rand-int 256)}))))
=> "232.2 MB"
为什么算法陷入泥淖中的时间和内存的大量帧的条款?什么是Clojure的做霸占这么多内存?
存储每个像素的哈希地图将会加起来非常快,如果每个1920×1080帧〜232 MB这是〜1 GB每4帧。我不认为这是特定的Clojure - 这是任何语言昂贵的存储方案。我会考虑几件事情:
(defrecord Pixel [r g b a])
(mem/measure (->Pixel (rand-int 256)
(rand-int 256)
(rand-int 256)
(rand-int 256)))
=> "112 B" ;; similar deftype is 96 B
四个甲原始整数数组只比单个Integer
对象稍大:
(mem/measure (int-array (range 4)))
=> "32 B"
类似的载体是10倍大的:
(mem/measure [(int 0) (int 1) (int 2) (int 3)])
=> "320 B"
你可以尝试字节数组,但JVM没有无符号字节原语:
(mem/measure (byte-array 4))
=> "24 B"
conj
'd到现有的载体,并且不来“免费”使用Clojure的持久数据结构。更有效的方式来做到这一点是使用transients,但...(defn gen-frame [num-pixels]
(repeatedly num-pixels
#(->Pixel (rand-int 256) (rand-int 256) (rand-int 256) (rand-int 256))))
(defn frame-op [frame] ;; not very interesting for random pixels
(let [num-pixels (count frame)
avg #(double (/ (apply + (map % frame)) num-pixels))]
(->Pixel (avg :r) (avg :g) (avg :b) (avg :a))))
(time
(->> (repeatedly #(gen-frame (* 1920 1080)))
(map frame-op)
(take 60)
(doall)))
"Elapsed time: 240527.803662 msecs"
=>
(#sandbox.core.Pixel{:r 127.4540152391975, :g 127.4542722800926, :b 127.3754962384259, :a 127.4886294367284}
#sandbox.core.Pixel{:r 127.4727488425926, :g 127.4447955246914, :b 127.4472164351852, :a 127.4626080246914}
...
这个例子是懒惰地分析一个无限序列的每个帧并取第一60点的结果;所分析的帧/像素数据是越来越收集垃圾,因为这运行,所以不会出的存储器中运行时(但GC将忙于)。这些参数解析为O(N)。
大常数关系,有时!
如果您需要什么,你可以走出@Taylor伍德回答的进一步加速,可以考虑进一步压缩存储。
如果你只是按99,Clojure的将存储作为java.lang.Long
,占用数每64个字节。使用java.lang.Integer
将削减在一半,占用了每号32个字节。
但是,我们有进一步优化的余地!你0和255之间生成数字,这意味着你需要每数量的存储log2(256) = 8
位。然后,我们可以容纳所有的三个RGB值到一个单一的java.lang.Integer
!
我下面就开始了。这种方法学分转到mikera/imagez。如果你喜欢扭捏多了,可以尽量避免我rem
和quot
的使用,去摆弄位代替。内存将是相同的,但CPU使用率会下降。
(defn encodable? [i]
(and (nat-int? i)
(< i 256)))
(defn rgb->int
"Store an RGB value in a single integer!"
[[r g b]]
(do (assert (encodable-int? r))
(assert (encodable-int? g))
(assert (encodable-int? b)))
(int
(+ (* 256 256 r)
(* 256 g)
b)))
(defn int->rbg [i]
[(rem (quot i (* 256 256)) 256)
(rem (quot i 256) 256)
(rem i 256)])
;; Let's try to store 99, 101, 255!
(def c [99 101 255])
(rgb->int c)
;; => 6514175
(type (rgb->int c))
;; => java.lang.Integer
(-> c rgb->int int->rbg)
;; => [99 101 255]