我正在用Clojure为一个程序编写一个基准测试。我有n
线程同时访问缓存。每个线程将访问缓存x
次。每个请求都应该记录在一个文件中。
为此,我创建了一个代理,它保存要写入的文件的路径。当我想写入时,send-off
是一个写入文件并简单返回路径的函数。我的文件以这种方式写入是无竞争条件的。
当我在没有代理的情况下执行代码时,它在几毫秒内就完成了。当我使用代理,并要求每个线程在每次我的代码运行非常慢时发送给代理时。我说了几分钟。
(defn load-cache-only [usercount cache-size]
"Test requesting from the cache only."
; Create the file to write the benchmark results to.
(def sink "benchmarks/results/load-cache-only.txt")
(let [data-agent (agent sink)
; Data for our backing store generated at runtime.
store-data (into {} (map vector (map (comp keyword str)
(repeat "item")
(range 1 cache-size))
(range 1 cache-size)))
cache (create-full-cache cache-size store-data)]
(barrier/run-with-barrier (fn [] (load-cache-only-work cache store-data data-agent)) usercount)))
(defn load-cache-only-work [cache store-data data-agent]
"For use with 'load-cache-only'. Requests each item in the cache one.
We time how long it takes for each request to be handled."
(let [cache-size (count store-data)
foreachitem (fn [cache-item]
(let [before (System/nanoTime)
result (cache/retrieve cache cache-item)
after (System/nanoTime)
diff_ms ((comp str float) (/ (- after before) 1000))]
;(send-off data-agent (fn [filepath]
;(file/insert-record filepath cache-size diff_ms)
;filepath))
))]
(doall (map foreachitem (keys store-data)))))
(barrier/run-with-barrier)
代码只生成usercount
数量的线程,并同时启动它们(使用原子(。我传递的函数是每个线程的主体。
正文将简单地映射到一个名为store-data
的列表上,这是一个键值列表(例如,{:a 1 :b 2}
。在我的代码中,这个列表的长度现在是10。用户数量也是10。
正如您所看到的,代理发送的代码被注释掉了。这使得代码能够正常执行。然而,当我启用发送时,即使没有写入文件,执行时间也太慢了。
编辑:
在他把每一条线索发给特工之前,我都会打印一个点。这些圆点的出现速度和没有送别时一样快。所以最后一定有什么阻碍。
我做错什么了吗?
如果希望JVM在合理的时间内退出,则在向代理发送完内容后需要调用(shutdown-agents)
。
潜在的问题是,如果不关闭代理,支持其线程池的线程将永远不会关闭,并阻止JVM退出。如果没有其他东西运行,会有一个超时来关闭池,但这相当长。生成操作后立即调用shutdown-agents
将解决此问题。