Saat ini saya memahami kerangka kerja Ekstensi Reaktif untuk .NET dan saya sedang mengerjakan berbagai sumber pengenalan yang saya temukan (terutama http://www.introtorx.com )
Aplikasi kami melibatkan sejumlah antarmuka perangkat keras yang mendeteksi bingkai jaringan, ini akan menjadi IObservables saya, saya kemudian memiliki berbagai komponen yang akan menggunakan bingkai tersebut atau melakukan beberapa cara mengubah data dan menghasilkan jenis bingkai baru. Juga akan ada komponen lain yang perlu menampilkan setiap bingkai ke-n misalnya. Saya yakin bahwa Rx akan berguna untuk aplikasi kita, namun saya kesulitan dengan detail implementasi untuk antarmuka IObserver.
Sebagian besar (jika tidak semua) sumber daya yang telah saya baca mengatakan bahwa saya tidak boleh mengimplementasikan antarmuka IObservable sendiri, tetapi menggunakan salah satu fungsi atau kelas yang disediakan. Dari penelitian saya, tampaknya membuat a Subject<IBaseFrame>
akan memberi saya apa yang saya butuhkan, saya akan memiliki utas tunggal yang membaca data dari antarmuka perangkat keras dan kemudian memanggil fungsi OnNext dari Subject<IBaseFrame>
instance saya . Komponen IObserver yang berbeda kemudian akan menerima notifikasi dari Subjek tersebut.
Kebingungan saya datang dari saran yang diberikan di lampiran tutorial ini di mana dikatakan:
Hindari penggunaan jenis subjek. Rx secara efektif merupakan paradigma pemrograman fungsional. Menggunakan subjek berarti kita sekarang mengelola status, yang berpotensi bermutasi. Berurusan dengan status mutasi dan pemrograman asynchronous pada saat yang sama sangat sulit dilakukan dengan benar. Selain itu, banyak operator (metode ekstensi) telah ditulis dengan cermat untuk memastikan bahwa masa pakai langganan dan urutan yang benar dan konsisten dipertahankan; saat Anda memperkenalkan subjek, Anda dapat memecahkannya. Rilis mendatang mungkin juga melihat penurunan performa yang signifikan jika Anda menggunakan subjek secara eksplisit.
Aplikasi saya cukup kritis terhadap kinerja, saya jelas akan menguji kinerja penggunaan pola Rx sebelum masuk ke kode produksi; namun saya khawatir bahwa saya melakukan sesuatu yang bertentangan dengan semangat kerangka kerja Rx dengan menggunakan kelas Subjek dan versi kerangka kerja yang akan datang akan merusak kinerja.
Adakah cara yang lebih baik untuk melakukan apa yang saya inginkan? Rangkaian polling perangkat keras akan terus berjalan baik ada pengamat atau tidak (buffer HW akan mencadangkan jika tidak), jadi ini adalah urutan yang sangat panas. Saya kemudian perlu meneruskan frame yang diterima ke beberapa pengamat.
Saran apa pun akan sangat dihargai.
sumber
Jawaban:
Oke, Jika kita mengabaikan cara dogmatis saya dan mengabaikan "subjek itu baik / buruk" secara bersamaan. Mari kita lihat ruang masalahnya.
Saya yakin Anda juga memiliki 1 dari 2 gaya sistem yang Anda butuhkan.
Untuk opsi 1, mudah, kita cukup membungkusnya dengan metode FromEvent yang sesuai dan selesai. Ke Pub!
Untuk opsi 2, sekarang kita perlu mempertimbangkan bagaimana kita melakukan polling ini dan bagaimana melakukannya dengan efisien. Juga ketika kita mendapatkan nilainya, bagaimana kita mempublikasikannya?
Saya akan membayangkan bahwa Anda menginginkan utas khusus untuk pemungutan suara. Anda tidak ingin pembuat kode lain memalu ThreadPool / TaskPool dan meninggalkan Anda dalam situasi kelaparan ThreadPool. Atau Anda tidak ingin kerumitan peralihan konteks (saya kira). Jadi asumsikan kita memiliki utas kita sendiri, kita mungkin akan memiliki semacam loop While / Sleep yang kita duduki untuk melakukan polling. Ketika pemeriksaan menemukan beberapa pesan, kami menerbitkannya. Semua ini terdengar sempurna untuk Observable.Create. Sekarang kita mungkin tidak bisa menggunakan loop While karena itu tidak akan memungkinkan kita untuk mengembalikan Disposable untuk memungkinkan pembatalan. Untungnya Anda telah membaca keseluruhan buku sehingga paham dengan penjadwalan rekursif!
Saya membayangkan sesuatu seperti ini bisa berhasil. #Tidak diuji
Alasan saya sangat tidak menyukai Subjek, adalah karena biasanya pengembang tidak memiliki desain yang jelas tentang masalah tersebut. Retas subjek, aduk di sana-sini dan di mana-mana, dan kemudian biarkan pengembang dukungan yang buruk menebak di WTF yang sedang terjadi. Ketika Anda menggunakan metode Buat / Hasilkan dll, Anda melokalkan efek pada urutan. Anda dapat melihat semuanya dalam satu metode dan Anda tahu tidak ada orang lain yang memberikan efek samping yang buruk. Jika saya melihat bidang subjek, sekarang saya harus mencari semua tempat di kelas yang sedang digunakan. Jika beberapa MFer mengeksposnya secara publik, maka semua taruhan dibatalkan, siapa yang tahu bagaimana urutan ini digunakan! Async / Concurrency / Rx sulit. Anda tidak perlu membuatnya lebih sulit dengan membiarkan efek samping dan pemrograman kausalitas semakin memusingkan kepala Anda.
sumber
Secara umum Anda harus menghindari penggunaan
Subject
, namun untuk hal yang Anda lakukan di sini saya pikir mereka bekerja dengan cukup baik. Saya mengajukan pertanyaan serupa ketika saya menemukan pesan "hindari subjek" di tutorial Rx.Mengutip Dave Sexton (dari Rxx)
Saya cenderung menggunakannya sebagai titik masuk ke Rx. Jadi jika saya memiliki beberapa kode yang perlu mengatakan 'sesuatu terjadi' (seperti yang Anda miliki), saya akan menggunakan
Subject
dan memanggilOnNext
. Kemudian tunjukkan itu sebagaiIObservable
langganan orang lain (Anda dapat menggunakanAsObservable()
subjek Anda untuk memastikan tidak ada yang dapat mentransmisikan ke Subjek dan mengacaukan semuanya).Anda juga dapat mencapai ini dengan acara dan penggunaan .NET
FromEventPattern
, tetapi jika saya hanya akan mengubah acara menjadi sebuahIObservable
, saya tidak melihat manfaat memiliki acara daripadaSubject
(yang mungkin berarti saya kehilangan sesuatu disini)Namun, yang harus Anda hindari cukup kuat adalah berlangganan
IObservable
dengan aSubject
, yaitu jangan meneruskan aSubject
ke dalamIObservable.Subscribe
metode.sumber
Seringkali ketika Anda mengelola sebuah Subjek, Anda sebenarnya hanya mengimplementasikan ulang fitur-fitur yang sudah ada di Rx, dan mungkin dengan cara yang tidak sekuat, sesederhana dan dapat diperluas.
Saat Anda mencoba menyesuaikan beberapa aliran data asinkron ke Rx (atau membuat aliran data asinkron dari salah satu yang saat ini tidak asinkron), kasus yang paling umum biasanya:
Sumber data adalah sebuah peristiwa : Seperti yang dikatakan Lee, ini adalah kasus yang paling sederhana: gunakan FromEvent dan pergi ke pub.
Sumber data berasal dari operasi sinkron dan Anda menginginkan pembaruan yang disurvei , (mis. Layanan web atau panggilan database): Dalam hal ini Anda dapat menggunakan pendekatan yang disarankan Lee, atau untuk kasus sederhana, Anda dapat menggunakan sesuatu seperti
Observable.Interval.Select(_ => <db fetch>)
. Anda mungkin ingin menggunakan DistinctUntilChanged () untuk mencegah publikasi pembaruan ketika tidak ada yang berubah dalam data sumber.Sumber data adalah sejenis api asinkron yang memanggil callback Anda : Dalam hal ini, gunakan Observable.Create untuk menghubungkan callback Anda untuk memanggil OnNext / OnError / OnComplete pada pengamat.
Sumber data adalah panggilan yang memblokir hingga data baru tersedia (misalnya, beberapa operasi pembacaan soket sinkron): Dalam kasus ini, Anda dapat menggunakan Observable.Create untuk menggabungkan kode penting yang membaca dari soket dan menerbitkannya ke Observer.OnNext saat data dibaca. Ini mungkin serupa dengan apa yang Anda lakukan dengan Subjek.
Menggunakan Observable.Create vs membuat kelas yang mengelola Subjek cukup setara dengan menggunakan kata kunci hasil vs membuat seluruh kelas yang mengimplementasikan IEnumerator. Tentu saja, Anda dapat menulis IEnumerator agar menjadi warga negara yang bersih dan sebaik kode hasil, tetapi mana yang lebih baik dikemas dan terasa desainnya lebih rapi? Hal yang sama berlaku untuk Observable. Buat vs mengelola Subjek.
Observable.Create memberi Anda pola yang bersih untuk pengaturan yang lambat dan pembongkaran yang bersih. Bagaimana Anda mencapai ini dengan kelas yang membungkus sebuah Subjek? Anda memerlukan semacam metode Mulai ... bagaimana Anda tahu kapan harus memanggilnya? Atau apakah Anda selalu memulainya, bahkan saat tidak ada yang mendengarkan? Dan ketika Anda sudah selesai, bagaimana Anda membuatnya berhenti membaca dari socket / polling database, dll? Anda harus memiliki semacam metode Berhenti, dan Anda masih harus memiliki akses tidak hanya ke IObservable langganan Anda, tetapi kelas yang membuat Subjek di tempat pertama.
Dengan Observable.Create, semuanya dibungkus di satu tempat. Badan Observable.Create tidak berjalan sampai seseorang berlangganan, jadi jika tidak ada yang berlangganan, Anda tidak pernah menggunakan sumber daya Anda. Dan Observable.Create mengembalikan Disposable yang dapat dengan bersih mematikan resource / callback Anda, dll - ini dipanggil saat Observer berhenti berlangganan. Umur sumber daya yang Anda gunakan untuk menghasilkan Observable terkait erat dengan masa Observable itu sendiri.
sumber
Teks blok yang dikutip cukup banyak menjelaskan mengapa Anda tidak boleh menggunakan
Subject<T>
, tetapi untuk membuatnya lebih sederhana, Anda menggabungkan fungsi pengamat dan yang dapat diamati, sambil memasukkan semacam status di antaranya (apakah Anda merangkum atau memperluas).Di sinilah Anda mengalami masalah; tanggung jawab ini harus terpisah dan berbeda satu sama lain.
Karena itu, dalam kasus khusus Anda , saya sarankan Anda memecah kekhawatiran Anda menjadi bagian-bagian yang lebih kecil.
Pertama, Anda memiliki utas Anda yang panas, dan selalu memantau perangkat keras untuk sinyal untuk menaikkan pemberitahuan. Bagaimana Anda biasanya melakukan ini? Acara . Jadi mari kita mulai dengan itu.
Mari kita tentukan
EventArgs
apakah acara Anda akan diaktifkan.Sekarang, kelas yang akan mengaktifkan acara tersebut. Catatan, ini bisa menjadi kelas statis (karena Anda selalu memiliki utas yang berjalan memantau buffer perangkat keras), atau sesuatu yang Anda panggil sesuai permintaan yang berlangganan itu . Anda harus memodifikasi ini sebagaimana mestinya.
Jadi sekarang Anda memiliki kelas yang mengekspos acara. Dapat diamati bekerja dengan baik dengan acara. Sedemikian rupa sehingga ada dukungan kelas satu untuk mengonversi aliran peristiwa (pikirkan aliran peristiwa sebagai beberapa pengaktifan peristiwa) menjadi
IObservable<T>
implementasi jika Anda mengikuti pola peristiwa standar, melalui metode statisFromEventPattern
diObservable
kelas .Dengan sumber acara Anda, dan
FromEventPattern
metode, kita dapat membuat denganIObservable<EventPattern<BaseFrameEventArgs>>
mudah (EventPattern<TEventArgs>
kelas mewujudkan apa yang Anda lihat dalam acara .NET, terutama, sebuah instance yang diturunkan dariEventArgs
dan objek yang mewakili pengirim), seperti:Tentu saja, Anda menginginkan
IObservable<IBaseFrame>
, tapi itu mudah, menggunakanSelect
metode ekstensi padaObservable
kelas untuk membuat proyeksi (seperti yang Anda lakukan di LINQ, dan kita bisa membungkus semua ini dengan metode yang mudah digunakan):sumber
IObservable<T>
sebagai tidak ada informasi tentang bagaimana Anda ' re saat ini memberi isyarat dengan informasi yang diberikan.Ini buruk untuk menggeneralisasi bahwa Subjek tidak baik digunakan untuk antarmuka publik. Meskipun memang benar, bahwa ini bukan cara pendekatan pemrograman reaktif seharusnya terlihat, namun secara definitif merupakan opsi perbaikan / pemfaktoran ulang yang baik untuk kode klasik Anda.
Jika Anda memiliki properti normal dengan aksesor kumpulan publik dan Anda ingin memberi tahu tentang perubahan, tidak ada yang melarang menggantinya dengan BehaviorSubject. INPC atau acara tambahan lainnya tidak begitu bersih dan secara pribadi membuat saya lelah. Untuk tujuan ini, Anda dapat dan harus menggunakan BehaviorSubjects sebagai properti publik, bukan properti normal, dan membuang INPC atau peristiwa lainnya.
Selain itu, antarmuka Subjek membuat pengguna antarmuka Anda lebih sadar tentang fungsionalitas properti Anda dan lebih cenderung untuk berlangganan daripada hanya mendapatkan nilainya.
Ini adalah yang terbaik untuk digunakan jika Anda ingin orang lain mendengarkan / berlangganan perubahan properti.
sumber