Clojure - Pemrograman Bersamaan
Dalam pemrograman Clojure sebagian besar tipe data tidak dapat diubah, jadi ketika datang ke pemrograman bersamaan, kode yang menggunakan tipe data ini cukup aman ketika kode berjalan pada banyak prosesor. Namun sering kali, ada persyaratan untuk berbagi data, dan ketika datang ke data bersama di beberapa prosesor, menjadi penting untuk memastikan bahwa status data dipertahankan dalam hal integritas saat bekerja dengan banyak prosesor. Ini dikenal sebagaiconcurrent programming dan Clojure memberikan dukungan untuk program semacam itu.
Sistem memori transaksional perangkat lunak (STM), diekspos melalui dosync, ref, set, alter, dll. Mendukung berbagi status perubahan antar utas secara sinkron dan terkoordinasi. Sistem agen mendukung berbagi perubahan status antar utas secara asinkron dan independen. Sistem atom mendukung berbagi perubahan keadaan antar utas secara sinkron dan independen. Sedangkan sistem var dinamis, yang diekspos melalui def, binding, dll. Mendukung pengisolasian status yang berubah di dalam utas.
Bahasa pemrograman lain juga mengikuti model untuk pemrograman konkuren.
Mereka memiliki referensi langsung ke data yang dapat diubah.
Jika akses bersama diperlukan, objek dikunci, nilainya diubah, dan proses berlanjut untuk akses berikutnya ke nilai itu.
Di Clojure tidak ada kunci, tetapi referensi tidak langsung ke struktur data persisten yang tidak dapat diubah.
Ada tiga jenis referensi di Clojure.
Vars - Perubahan diisolasi dalam utas.
Refs - Perubahan disinkronkan dan dikoordinasikan antar utas.
Agents - Melibatkan perubahan independen asinkron antar utas.
Operasi berikut dimungkinkan di Clojure yang berkaitan dengan pemrograman bersamaan.
Transaksi
Concurrency di Clojure didasarkan pada transaksi. Referensi hanya dapat diubah dalam satu transaksi. Aturan berikut diterapkan dalam transaksi.
- Semua perubahan bersifat atom dan terisolasi.
- Setiap perubahan referensi terjadi dalam transaksi.
- Tidak ada transaksi yang melihat efek yang dibuat oleh transaksi lain.
- Semua transaksi ditempatkan di dalam blok dosync.
Kita sudah melihat apa yang dilakukan blok dosync, mari kita lihat lagi.
dosync
Menjalankan ekspresi (dalam do implisit) dalam transaksi yang mencakup ekspresi dan panggilan bertingkat apa pun. Memulai transaksi jika belum ada yang berjalan di utas ini. Pengecualian yang tidak tertangkap akan membatalkan transaksi dan keluar dari dosync.
Berikut adalah sintaksnya.
Sintaksis
(dosync expression)
Parameters - 'Ekspresi' adalah himpunan ekspresi yang akan ada di blok dosync.
Return Value - Tidak ada.
Mari kita lihat contoh di mana kami mencoba mengubah nilai variabel referensi.
Contoh
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(alter names conj "Mark"))
(Example)
Keluaran
Program di atas saat dijalankan memberikan kesalahan berikut.
Caused by: java.lang.IllegalStateException: No transaction running
at clojure.lang.LockingTransaction.getEx(LockingTransaction.java:208)
at clojure.lang.Ref.alter(Ref.java:173)
at clojure.core$alter.doInvoke(core.clj:1866)
at clojure.lang.RestFn.invoke(RestFn.java:443)
at clojure.examples.example$Example.invoke(main.clj:5)
at clojure.examples.example$eval8.invoke(main.clj:7)
at clojure.lang.Compiler.eval(Compiler.java:5424)
... 12 more
Dari kesalahan tersebut Anda dapat dengan jelas melihat bahwa Anda tidak dapat mengubah nilai tipe referensi tanpa terlebih dahulu memulai transaksi.
Agar kode di atas berfungsi, kita harus menempatkan perintah alter di blok dosync seperti yang dilakukan di program berikut.
Contoh
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(defn change [newname]
(dosync
(alter names conj newname)))
(change "John")
(change "Mark")
(println @names))
(Example)
Program di atas menghasilkan keluaran sebagai berikut.
Keluaran
[John Mark]
Mari kita lihat contoh lain dari dosync.
Contoh
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def var1 (ref 10))
(def var2 (ref 20))
(println @var1 @var2)
(defn change-value [var1 var2 newvalue]
(dosync
(alter var1 - newvalue)
(alter var2 + newvalue)))
(change-value var1 var2 20)
(println @var1 @var2))
(Example)
Dalam contoh di atas, kami memiliki dua nilai yang diubah dalam blok dosync. Jika transaksi berhasil, kedua nilai akan berubah jika tidak maka seluruh transaksi akan gagal.
Program di atas menghasilkan keluaran sebagai berikut.
Keluaran
10 20
-10 40