Saya sedang mencari alasan mengapa. NET CancellationToken
struct diperkenalkan di samping CancellationTokenSource
kelas. Saya mengerti bagaimana API akan digunakan, tetapi ingin juga memahami mengapa itu dirancang seperti itu.
Yaitu, mengapa kita memiliki:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);
...
public void SomeCancellableOperation(CancellationToken token) {
...
token.ThrowIfCancellationRequested();
...
}
bukannya langsung lewat CancellationTokenSource
seperti:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);
...
public void SomeCancellableOperation(CancellationTokenSource cts) {
...
cts.ThrowIfCancellationRequested();
...
}
Apakah ini optimasi kinerja berdasarkan pada fakta bahwa pembatalan pemeriksaan pembatalan terjadi lebih sering daripada melewati token?
Sehingga CancellationTokenSource
dapat melacak dan memperbarui CancellationTokens
, dan untuk setiap token cek pembatalan adalah akses bidang lokal?
Mengingat bahwa bool volatil tanpa penguncian sudah cukup dalam kedua kasus, saya masih tidak bisa melihat mengapa itu akan lebih cepat
Terima kasih!
sumber
Saya punya pertanyaan yang tepat dan saya ingin memahami alasan di balik desain ini.
Jawaban yang diterima mendapatkan alasan yang tepat. Berikut konfirmasi dari tim yang merancang fitur ini (penekanan pada saya):
Tautan: .NET 4 Framework Framework
Menurut saya, fakta yang
CancellationToken
hanya bisa mengamati negara dan tidak mengubahnya, sangat kritis. Anda dapat membagikan token seperti permen dan tidak pernah khawatir bahwa orang lain, selain Anda, akan membatalkannya. Ini melindungi Anda dari kode pihak ketiga yang bermusuhan. Ya, peluangnya tipis, tapi saya pribadi suka jaminan itu.Saya juga merasa bahwa itu membuat API lebih bersih dan menghindari kesalahan tak disengaja dan mempromosikan desain komponen yang lebih baik.
Mari kita lihat API publik untuk kedua kelas ini.
Jika Anda menggabungkannya, saat menulis LongRunningFunction, saya akan melihat metode seperti beberapa overload 'Batalkan' yang seharusnya tidak saya gunakan. Secara pribadi, saya benci melihat metode Buang juga.
Saya pikir desain kelas saat ini mengikuti filosofi 'lubang keberhasilan', itu memandu pengembang untuk membuat komponen yang lebih baik yang dapat menangani
Task
pembatalan dan kemudian menyatukan mereka dalam berbagai cara untuk membuat alur kerja yang rumit.Izinkan saya mengajukan pertanyaan, apakah Anda bertanya-tanya apa tujuan token? Itu tidak masuk akal bagi saya. Dan kemudian saya membaca Pembatalan di Thread yang Dikelola dan semuanya menjadi sangat jelas.
Saya percaya bahwa Desain Kerangka Pembatalan di TPL benar-benar kedudukan tertinggi.
sumber
CancellationTokenSource
sebenarnya dapat memulai permintaan membatalkan pada token yang terkait (token tidak dapat melakukannya sendiri): The CancellToken memiliki konstruktor internal ini:internal CancellationToken(CancellationTokenSource source) { this.m_source = source; }
dan properti ini:public bool IsCancellationRequested { get { return this.m_source != null && this.m_source.IsCancellationRequested; } }
The CancellTokenSource menggunakan konstruktor internal, sehingga token memiliki referensi ke source (m_source)Mereka terpisah bukan karena alasan teknis tetapi yang semantik. Jika Anda melihat implementasi di
CancellationToken
bawah ILSpy, Anda akan menemukan itu hanya pembungkusCancellationTokenSource
(dan dengan demikian tidak ada perbedaan kinerja-bijaksana daripada membagikan referensi).Mereka menyediakan pemisahan fungsi ini untuk membuat hal-hal lebih dapat diprediksi: ketika Anda melewati suatu metode
CancellationToken
, Anda tahu Anda masih satu-satunya yang dapat membatalkannya. Tentu, metode ini masih bisa melemparTaskCancelledException
, tetapi metodeCancellationToken
itu sendiri - dan metode lain yang merujuk token yang sama - akan tetap aman.sumber
CancellationTokenSource
. Anda akan berpikir Anda bisa mengatakan "jangan lakukan itu", tetapi orang-orang (termasuk saya!) Kadang-kadang melakukan hal-hal ini untuk mendapatkan beberapa fungsi tersembunyi, dan itu akan terjadi. Setidaknya itulah teori saya saat ini.Ini
CancellationToken
adalah struct sehingga banyak salinan bisa ada karena meneruskannya ke metode.Set
CancellationTokenSource
menetapkan status SEMUA salinan token saat memanggilCancel
sumber. Lihat halaman MSDN iniAlasan untuk desain mungkin hanya masalah pemisahan kekhawatiran dan kecepatan struct.
sumber
The
CancellationTokenSource
adalah 'hal' bahwa isu-isu pembatalan, untuk alasan apapun. Perlu cara untuk 'mengirim' pembatalan itu ke semua yangCancellationToken
telah dikeluarkan. Begitulah cara, misalnya, ASP.NET dapat membatalkan operasi ketika permintaan dibatalkan. Setiap permintaan memilikiCancellationTokenSource
yang meneruskan pembatalan ke semua token yang telah dikeluarkannya.Ini bagus untuk pengujian unit BTW - buat sumber token pembatalan Anda sendiri, dapatkan token, panggil
Cancel
sumbernya, dan berikan token ke kode Anda yang harus menangani pembatalan tersebut.sumber