2013-08-26 4 views
0

Я бы хотел найти самый быстрый способ генерации списка ленивых чисел в clojure. В настоящее время я использую следующее:Самый быстрый способ генерации списка ленивых чисел

(doall (take 5000000 (iterate inc 5000000000))) 

, чтобы создать нелогичный список номеров от 5 до 5,005 миллиарда. Есть ли более быстрые способы сделать это? Благодаря

(п.с. я в курсе, что с помощью списков для хранения последовательности чисел неоптимальное. Однако я использую это в качестве ориентира для Shen.java компилятора)

+0

Вам нужен быстрый способ заполнения медленной структуры данных? –

+2

Вы можете указать начало и конец (и шаг) с помощью 'range'. –

+0

@AlisterLee: быстрый способ не быстрый. Я знал, что мой подход не был самым быстрым подходом к заполнению списка – artella

ответ

2

Фактически, doall отлично работает. Единственная проблема с вашим примером - медленная функция iterate. Вы должны использовать range вместо него:

(doall (range 5000000000 5005000000)) 

range очень быстро. Это лениво, но он оптимизирован и генерирует числа в кусках.

Вот результаты тестов для iterate и run, полученные с помощью criterium:

user=> (quick-bench (doall (take 5000 (iterate inc 5000000)))) 
Evaluation count : 180 in 6 samples of 30 calls. 
      Execution time mean : 3.175749 ms 
    Execution time std-deviation : 1.179449 ms 
    Execution time lower quantile : 2.428681 ms (2.5%) 
    Execution time upper quantile : 4.735748 ms (97.5%) 
        Overhead used : 14.758153 ns 

user=> (quick-bench (doall (range 5000000 5005000))) 
Evaluation count : 672 in 6 samples of 112 calls. 
      Execution time mean : 1.253228 ms 
    Execution time std-deviation : 350.301594 µs 
    Execution time lower quantile : 845.026223 µs (2.5%) 
    Execution time upper quantile : 1.582950 ms (97.5%) 
        Overhead used : 14.758153 ns 

Как вы можете видеть, range в 2,5 раза быстрее, чем iterate здесь.

На моем компьютере требуется меньше секунды, чтобы сгенерировать все 5000000 номеров, но есть некоторые трюки, чтобы заставить его работать еще быстрее.

Например, вы можете запустить генерацию в отдельном потоке:

(let [numbers (range 5000000000 5005000000)] 
    (future (dorun numbers)) 
    ...) 

Он не будет делать поколение быстрее, но вы будете иметь возможность немедленно использовать последовательность, прежде чем она будет полностью -realized.

+0

Это замечательное спасибо. Shen.java изначально делал это в 4s, тогда как использование clojure итерации занимало 7 секунд, и я знал, что, наверное, слишком медленно делал версию clojure! – artella

+1

Строго говоря, этот ответ связан с созданием и реализацией [** sequence **] (http://clojure.org/sequences), не создающей [** list **] (http://clojure.org/data_structures # Data% 20Structures-Lists% 20 (IPersistentList)), как указано в заголовке. Для списка вам нужно будет сделать что-то вроде '(в '() (диапазон 5000000000 5005000000))' (или '(в'() (диапазон 5005000000 5000000000 -1))' для сохранения порядка). Но, как я понимаю из контекста, это не то, что вам нужно здесь. –

+0

@ PawełŁoziński Спасибо, что мне нужен список. Теперь clojure занимает около 4 с, что наравне с Shen.java. – artella

0

DOALL обычно что тебе нужно. Но что вы подразумеваете под «самым быстрым»? быстрее в контексте производительности или в контексте кодирования?

+3

Это ответ или комментарий? –

Смежные вопросы