Qanday Clojure fyuchersini bitta ishni bajarish mumkin?

Men Clojure'da biroz muddatli fursat yaratmoqchiman va ularni bir vaqtning o'zida ishlashiga ishonch hosil qilish uchun hammasini muayyan bir mavzu bilan boshqarishni istayman. Bu mumkinmi?

Buni amalga oshirish uchun Java kutubxonalarini o'rash qiyin emas, lekin buni amalga oshirishdan oldin, uni amalga oshirish uchun Clojure usulidan foydalanmayotganimga ishonch hosil qilishni xohlayman. Java'da men buni FutureTask amalga oshirish va bu vazifalarni bitta ishlangan ijrochiga yuborish orqali amalga oshirishim mumkin.

0
Nimaga bir vaqtning o'zida amalga oshirilishini ta'minlash uchun, ular o'zaro kelishuvga mo'ljallangan tuzilmalarni yaratishni xohlaysiz? Ehtimol, sizda bu kabi vazifalarni belgilashingiz mumkin yoki odatda ularni bir vaqtning o'zida bajarasiz, lekin cheklangan vaqt uchun ketma-ket ijro etilishini majbur qilmoqchimisiz? Faqat qiziq.
qo'shib qo'ydi muallif Josh, manba
Albatta, lekin bu holatda nima uchun ish zarralarini yaratasiz? Nima uchun vazifalarni bitta ish zarrachasidan vazifalar deb ataymiz?
qo'shib qo'ydi muallif Josh, manba
Bir vaqtning o'zida bir nechta ish zarrachalari tomonidan ishlatilishi mumkin bo'lgan umumiy resurs Xni ishlatadigan vazifalarni bajarishni xohlaydigan ko'plab masalalar (masalan, serverdagi so'rovlar) mavjudligini aytishimiz mumkin. Bir echim X ga kirganda qulfni yopishdir. Boshqacha qilib aytganda, vazifalar (fyuchers) X bilan bog'liq bo'lgan bitta ishni bajarish uchun topshirishdir. Boshqa chaqiruvlar esa kelajakdagi natijalarni kutishlari yoki kutmasligi mumkin.
qo'shib qo'ydi muallif Rob N, manba
Menimcha, qisqa javob: tizim boshqa sohalarda parallel ijro etilishidan foyda ko'radi. Alohida mavzularda ishlov berilgan murojaatlar bilan veb-server kabi. So'ngra, bu iplar manba X dan foydalanadigan narsalarni qilishlari kerak. Bu fikr men ixtiro qilgan narsa emas - bu Apple GCDdan asyncha yuborilgan ketma-ket navbat. Ehtimol, ushbu tizim uchun hujjat uni yaxshiroq tushuntirishi mumkin. developer.apple.com/documentation/dispatch
qo'shib qo'ydi muallif Rob N, manba

8 javoblar

Clojurening kelajakdagi so'l , kelajakdagi qo'ng'iroq funktsiyasi /clj/clojure/core.clj#L6848 "rel =" nofollow noreferrer "> maxsus ijrochi xizmati . Bu sizning ketma-ket ijro etilishini amalga oshirish uchun hech qanday nazoratga ega emasligingizni bildiradi.

Boshqa tomondan future moslamalari o'rniga so'zni ishlatishingiz mumkin. bir future ipini ketma-ket ravishda taslim qilish natijalarini taqdim etishingiz mumkin. Promise API'si future s taqdim etgan narsaga o'xshaydi. Ular deref va amalga oshdi? .

Quyidagi kod misoli pastki vazifalar ketma-ketlikda yangi ish zarrachalarida bajarilgan bo'lsa, funktsiyaning darhol qaytarilgan natijasi hisoblangan qiymatlar uchun va'dalarni o'z ichiga oladi.

(defn start-async-calc []
  (let [f1 (promise)
        f2 (promise)
        f3 (promise)]
    (future
      (deliver f1 (task-1))
      (deliver f2 (task-2))
      (deliver f3 (task-3)))
    {:task1 f1
     :task2 f2
     :task3 f3}))
2
qo'shib qo'ydi

Clojurening kelajakdagi so'l , kelajakdagi qo'ng'iroq funktsiyasi /clj/clojure/core.clj#L6848 "rel =" nofollow noreferrer "> maxsus ijrochi xizmati . Bu sizning ketma-ket ijro etilishini amalga oshirish uchun hech qanday nazoratga ega emasligingizni bildiradi.

Boshqa tomondan future moslamalari o'rniga so'zni ishlatishingiz mumkin. bir future ipini ketma-ket ravishda taslim qilish natijalarini taqdim etishingiz mumkin. Promise API'si future s taqdim etgan narsaga o'xshaydi. Ular deref va amalga oshdi? .

Quyidagi kod misoli pastki vazifalar ketma-ketlikda yangi ish zarrachalarida bajarilgan bo'lsa, funktsiyaning darhol qaytarilgan natijasi hisoblangan qiymatlar uchun va'dalarni o'z ichiga oladi.

(defn start-async-calc []
  (let [f1 (promise)
        f2 (promise)
        f3 (promise)]
    (future
      (deliver f1 (task-1))
      (deliver f2 (task-2))
      (deliver f3 (task-3)))
    {:task1 f1
     :task2 f2
     :task3 f3}))
2
qo'shib qo'ydi

agar future ga qo'ng'iroqlarni ketma-ketlashtirishni istasangiz, mana bu tarzda foydalanishingiz mumkin:

(do @(future 1)
    @(future 2)
    @(future 3))

ular, ehtimol, turli xil mavzularda chaqirishlari mumkin edi, ammo oldingi ishi tugamagunga qadar keyingi biri chaqirilmaydi. Bu kod @ (yoki deref funktsiyasi) tomonidan kafolatlanadi. Bu do shaklini amalga oshiradigan ish zarra tugamasdan oldin oldingi so'z bilan to'sib qo'yilishi va keyin keyingi qismini ochish degan ma'noni anglatadi.

bu kabi makro bilan uni prettiya qilishingiz mumkin:

(defmacro sequentialize [& futures]
  `(do [email protected](map #(list `deref %) futures)))

user> (let [a (atom 1)]
        (sequentialize
         (future (swap! a #(* 10 %)))
         (future (swap! a #(+ 20 %)))
         (future (swap! a #(- %))))
        @a)
;;=> -30

bu qo'lda do bilan bir xil bo'ladi. Shuni e'tiborga olingki, a atomiga bo'lgan mutatsiyalar bir nechta ish zarbasi ko'proq bo'lsa ham tartibga solinadi:

user> (let [a (atom 1)]
        (sequentialize
         (future (Thread/sleep 100)
                 (swap! a #(* 10 %)))
         (future (Thread/sleep 200)
                 (swap! a #(+ 20 %)))
         (future (swap! a #(- %))))
        @a)
;;=> -30
1
qo'shib qo'ydi

agar future ga qo'ng'iroqlarni ketma-ketlashtirishni istasangiz, mana bu tarzda foydalanishingiz mumkin:

(do @(future 1)
    @(future 2)
    @(future 3))

ular, ehtimol, turli xil mavzularda chaqirishlari mumkin edi, ammo oldingi ishi tugamagunga qadar keyingi biri chaqirilmaydi. Bu kod @ (yoki deref funktsiyasi) tomonidan kafolatlanadi. Bu do shaklini amalga oshiradigan ish zarra tugamasdan oldin oldingi so'z bilan to'sib qo'yilishi va keyin keyingi qismini ochish degan ma'noni anglatadi.

bu kabi makro bilan uni prettiya qilishingiz mumkin:

(defmacro sequentialize [& futures]
  `(do [email protected](map #(list `deref %) futures)))

user> (let [a (atom 1)]
        (sequentialize
         (future (swap! a #(* 10 %)))
         (future (swap! a #(+ 20 %)))
         (future (swap! a #(- %))))
        @a)
;;=> -30

bu qo'lda do bilan bir xil bo'ladi. Shuni e'tiborga olingki, a atomiga bo'lgan mutatsiyalar bir nechta ish zarbasi ko'proq bo'lsa ham tartibga solinadi:

user> (let [a (atom 1)]
        (sequentialize
         (future (Thread/sleep 100)
                 (swap! a #(* 10 %)))
         (future (Thread/sleep 200)
                 (swap! a #(+ 20 %)))
         (future (swap! a #(- %))))
        @a)
;;=> -30
1
qo'shib qo'ydi

Bunga qo'shimcha ravishda so'zlar so'zidan foydalangan holda delay dan foydalanishingiz mumkin. Va'dalar siz tasodifan ularni taslim qilmaslik va future s va delay s bilan mumkin bo'lmagan o'chirib qo'yiladigan ssenariyni yaratishingiz mumkin. Kelajak va kechikish o'rtasidagi farq faqatgina bajarilgan ish zarrachalaridir. Kelajakka erishish uchun, ish fonda amalga oshiriladi va kechiktirilishi bilan, ishni bajarishdan bosh tortadigan birinchi ishchi tomonidan amalga oshiriladi. Agar kelajak kelajakdagi va'dalarga qaraganda yaxshiroq bo'lsa, siz har doim shunday narsalarni qilishingiz mumkin:

(def result-1 (delay (long-calculation-1)))
(def result-2 (delay (long-calculation-2)))
(def result-3 (delay (long-calculation-3)))

(defn run-calcs []
  @(future
     @result-1
     @result-2
     @result-3))
0
qo'shib qo'ydi

Bunga qo'shimcha ravishda so'zlar so'zidan foydalangan holda delay dan foydalanishingiz mumkin. Va'dalar siz tasodifan ularni taslim qilmaslik va future s va delay s bilan mumkin bo'lmagan o'chirib qo'yiladigan ssenariyni yaratishingiz mumkin. Kelajak va kechikish o'rtasidagi farq faqatgina bajarilgan ish zarrachalaridir. Kelajakka erishish uchun, ish fonda amalga oshiriladi va kechiktirilishi bilan, ishni bajarishdan bosh tortadigan birinchi ishchi tomonidan amalga oshiriladi. Agar kelajak kelajakdagi va'dalarga qaraganda yaxshiroq bo'lsa, siz har doim shunday narsalarni qilishingiz mumkin:

(def result-1 (delay (long-calculation-1)))
(def result-2 (delay (long-calculation-2)))
(def result-3 (delay (long-calculation-3)))

(defn run-calcs []
  @(future
     @result-1
     @result-2
     @result-3))
0
qo'shib qo'ydi

Manifold provides a way to create future with specific executor. It's not part of core Clojure lib, but it's still a high quality lib and probably a best option in case you need more flexibility dealing with futures than core lib provides (without resorting to Java interop).

0
qo'shib qo'ydi

Manifold provides a way to create future with specific executor. It's not part of core Clojure lib, but it's still a high quality lib and probably a best option in case you need more flexibility dealing with futures than core lib provides (without resorting to Java interop).

0
qo'shib qo'ydi