Saya telah mencari di buku Swift, tetapi tidak dapat menemukan versi Swift dari @sinkronisasi. Bagaimana saya melakukan pengecualian bersama dalam Swift?
concurrency
mutex
swift
Tagihan
sumber
sumber
removeFirst()
?Jawaban:
Anda bisa menggunakan GCD. Ini sedikit lebih verbose daripada
@synchronized
, tetapi berfungsi sebagai pengganti:sumber
Saya sendiri sedang mencari ini dan sampai pada kesimpulan belum ada konstruksi asli dalam swift untuk ini.
Saya membuat fungsi pembantu kecil ini berdasarkan pada beberapa kode yang saya lihat dari Matt Bridges dan yang lainnya.
Penggunaannya cukup mudah
Ada satu masalah yang saya temukan dengan ini. Melewati dalam array sebagai argumen kunci tampaknya menyebabkan kesalahan kompiler yang sangat tumpul pada saat ini. Kalau tidak, tampaknya berfungsi seperti yang diinginkan.
sumber
@synchronized
blok dengan baik, tetapi perhatikan bahwa itu tidak identik dengan pernyataan blok builtin nyata seperti@synchronized
blok di Objective-C, karenareturn
danbreak
pernyataan tidak lagi berfungsi untuk melompat keluar dari fungsi / loop di sekitarnya seperti itu akan terjadi jika ini adalah pernyataan biasa.defer
kata kunci baru untuk memastikanobjc_sync_exit
dipanggil bahkan jikaclosure
melempar.Saya suka dan menggunakan banyak jawaban di sini, jadi saya akan memilih mana yang paling cocok untuk Anda. Yang mengatakan, metode yang saya sukai ketika saya membutuhkan sesuatu seperti objektif-c
@synchronized
menggunakandefer
pernyataan yang diperkenalkan di Swift 2.Bagus hal tentang metode ini, adalah bahwa bagian kritis Anda dapat keluar blok yang mengandung dalam setiap busana yang diinginkan (misalnya,
return
,break
,continue
,throw
), dan "laporan dalam pernyataan defer dijalankan tidak peduli bagaimana kontrol program ditransfer." 1sumber
lock
? Bagaimanalock
diinisialisasi?lock
adalah objek objektif-c.Anda dapat menjepit pernyataan antara
objc_sync_enter(obj: AnyObject?)
danobjc_sync_exit(obj: AnyObject?)
. Kata kunci @sinkronisasi menggunakan metode-metode di bawah penutup. yaitusumber
objc_sync_enter
danobjc_sync_exit
apakah metode didefinisikan dalam Objc-sync.h dan merupakan sumber terbuka: opensource.apple.com/source/objc4/objc4-371.2/runtime/…objc_sync_enter(…)
&objc_sync_exit(…)
adalah tajuk publik yang disediakan oleh iOS / macOS / etc. API (sepertinya ada di dalam….sdk
di jalurusr/include/objc/objc-sync.h
) . Cara termudah untuk mengetahui apakah sesuatu adalah API publik atau tidak adalah dengan (dalam Xcode) ketik nama fungsi (misalnyaobjc_sync_enter()
; argumen tidak perlu ditentukan untuk fungsi C) , lalu coba klik perintah. Jika itu menunjukkan kepada Anda file header untuk API itu, maka Anda baik (karena Anda tidak akan dapat melihat header jika itu tidak publik) .Analog
@synchronized
arahan dari Objective-C dapat memiliki jenis pengembalian sewenang-wenang danrethrows
perilaku yang baik di Swift.Penggunaan
defer
pernyataan memungkinkan untuk secara langsung mengembalikan nilai tanpa memperkenalkan variabel sementara.Di Swift 2 tambahkan
@noescape
atribut ke penutupan untuk memungkinkan lebih banyak optimisasi:Berdasarkan jawaban dari GNewc [1] (di mana saya suka tipe pengembalian sewenang-wenang) dan Tod Cunningham [2] (di mana saya suka
defer
).sumber
SWIFT 4
Di Swift 4 Anda dapat menggunakan antrian pengiriman GCD untuk mengunci sumber daya.
sumber
.serial
tampaknya tidak tersedia. Tetapi.concurrent
tersedia. : /myObject.state = myObject.state + 1
secara bersamaan, itu tidak akan menghitung total operasi tetapi menghasilkan nilai nondeterministic. Untuk mengatasi masalah itu, kode panggilan harus dibungkus dalam antrian serial sehingga membaca dan menulis terjadi secara atomis. Tentu saja Obj-c@synchronised
memiliki masalah yang sama, jadi dalam arti implementasi Anda sudah benar.myObject.state += 1
merupakan kombinasi dari operasi baca dan kemudian penulisan. Beberapa utas lainnya masih dapat datang di antara untuk menetapkan / menulis nilai. Sesuai objc.io/blog/2018/12/18/atomic-variables , akan lebih mudah untuk menjalankanset
blok / penutupan sinkronisasi sebagai gantinya dan tidak di bawah variabel itu sendiri.Menggunakan jawaban Bryan McLemore, saya memperluasnya untuk mendukung benda-benda yang melemparkan manor yang aman dengan kemampuan menunda Swift 2.0.
sumber
rethrows
untuk menyederhanakan penggunaan dengan penutupan non-lempar (tidak perlu digunakantry
), seperti yang ditunjukkan dalam jawaban saya .Untuk menambahkan fungsionalitas pengembalian, Anda dapat melakukan ini:
Selanjutnya, Anda dapat memanggilnya menggunakan:
sumber
Cepat 3
Kode ini memiliki kemampuan masuk kembali dan dapat bekerja dengan panggilan fungsi Asynchronous. Dalam kode ini, setelah someAsyncFunc () dipanggil, penutupan fungsi lain pada antrian serial akan memproses tetapi diblokir oleh semaphore.wait () hingga signal () dipanggil. internalQueue.sync tidak boleh digunakan karena akan memblokir utas utama jika saya tidak salah.
objc_sync_enter / objc_sync_exit bukan ide yang baik tanpa penanganan kesalahan.
sumber
Dalam sesi "Memahami Kecelakaan dan Kecelakaan" 414 dari WWDC 2018, mereka menunjukkan cara berikut menggunakan DispatchQueues dengan sinkronisasi.
Di swift 4 harus seperti ini:
Pokoknya Anda juga dapat membuat pembacaan lebih cepat menggunakan antrian bersamaan dengan hambatan. Sinkronisasi dan pembacaan async dilakukan bersamaan dan menulis nilai baru menunggu operasi sebelumnya selesai.
sumber
Gunakan NSLock di Swift4:
sumber
Di Swift 5 modern, dengan kemampuan pengembalian:
Gunakan seperti ini, untuk memanfaatkan kapabilitas nilai pengembalian:
Atau seperti itu sebaliknya:
sumber
GCD
). Tampaknya pada dasarnya tidak ada yang menggunakan atau mengerti cara menggunakannyaThread
. Saya senang dengan itu - sedangkanGCD
penuh dengan gotcha dan keterbatasan.Coba: NSRecursiveLock
sumber
Gambar Saya akan memposting implementasi Swift 5 saya, dibangun dari jawaban sebelumnya. Terima kasih kawan! Saya merasa terbantu memiliki satu yang mengembalikan nilai juga, jadi saya punya dua metode.
Berikut ini adalah kelas sederhana yang harus dibuat terlebih dahulu:
Kemudian gunakan seperti itu jika membutuhkan nilai kembali:
Atau:
sumber
public class func synced<T>(_ lock: Any, closure: () -> T)
, bekerja untuk keduanya, batal dan jenis lainnya. Ada juga hal-hal yang tumbuh kembali.Detail
xCode 8.3.1, cepat 3.1
Tugas
Baca nilai tulis dari utas berbeda (async).
Kode
Pemakaian
Sampel Lengkap
sumber
Dengan pembungkus properti Swift, inilah yang saya gunakan sekarang:
Maka Anda bisa melakukan:
atau
Kemudian akses variabel seperti biasa.
sumber
DispatchQueue
yang tersembunyi dari pengguna. Saya menemukan referensi SO ini untuk menenangkan pikiran saya: stackoverflow.com/a/35022486/1060314Kesimpulannya, Di sini memberikan cara yang lebih umum yang mencakup nilai balik atau batal, dan melempar
sumber
Mengapa membuatnya sulit dan repot dengan kunci? Gunakan Dispatch Barriers.
Penghalang pengiriman membuat titik sinkronisasi dalam antrian bersamaan.
Ketika sedang berjalan, tidak ada blok lain di antrian yang diizinkan untuk berjalan, bahkan jika itu bersamaan dan inti lainnya tersedia.
Jika itu terdengar seperti kunci (tulis) eksklusif, ya. Blok non-penghalang dapat dianggap sebagai kunci bersama (baca).
Selama semua akses ke sumber daya dilakukan melalui antrian, hambatan menyediakan sinkronisasi yang sangat murah.
sumber
Berdasarkan ɲeuroburɳ , uji kasus kelas bawah
Keluaran:
sumber
dispatch_barrier_async adalah cara yang lebih baik, sementara tidak memblokir utas saat ini.
dispatch_barrier_async (accessQueue, {dictionary [object.ID] = object})
sumber
Metode lain adalah membuat superclass dan kemudian mewarisinya. Dengan cara ini Anda dapat menggunakan GCD secara langsung
sumber