Saya ingin menunggu Tugas <T> diselesaikan dengan beberapa aturan khusus: Jika belum selesai setelah X milidetik, saya ingin menampilkan pesan kepada pengguna. Dan jika belum selesai setelah Y milidetik, saya ingin secara otomatis meminta pembatalan .
Saya bisa menggunakan Task.ContinueWith untuk secara asinkron menunggu tugas selesai (yaitu menjadwalkan tindakan yang akan dieksekusi ketika tugas selesai), tetapi itu tidak memungkinkan untuk menentukan batas waktu. Saya bisa menggunakan Task.Wait untuk secara sinkron menunggu tugas selesai dengan batas waktu, tetapi itu memblokir utas saya. Bagaimana saya bisa tidak sinkron menunggu tugas selesai dengan batas waktu?
CancellationTokenSource
. Tersedia dua overload ke konstruktor, satu mengambil bilangan bulat milidetik integer dan satu mengambil penundaan TimeSpan.Jawaban:
Bagaimana dengan ini:
Dan di sini ada posting blog yang bagus "Crafting a Task.TimeoutAfter Method" (dari tim MS Parallel Library) dengan info lebih lanjut tentang hal semacam ini .
Tambahan : atas permintaan komentar pada jawaban saya, berikut ini adalah solusi diperluas yang mencakup penanganan pembatalan. Perhatikan bahwa meneruskan pembatalan ke tugas dan timer berarti bahwa ada beberapa cara pembatalan dapat dialami dalam kode Anda, dan Anda harus yakin untuk menguji dan yakin Anda menangani semuanya dengan benar. Jangan biarkan berbagai kombinasi kebetulan dan berharap komputer Anda melakukan hal yang benar saat runtime.
sumber
Task.Delay
tugas didukung oleh pengatur waktu sistem yang akan terus dilacak sampai batas waktu berakhir terlepas dari berapa lamaSomeOperationAsync
. Jadi, jika potongan kode keseluruhan ini banyak dieksekusi dalam loop ketat, Anda menghabiskan sumber daya sistem untuk pengatur waktu hingga habis waktu. Cara untuk memperbaikinya adalah denganCancellationToken
mengirimkannya keTask.Delay(timeout, cancellationToken)
yang Anda batalkan saatSomeOperationAsync
selesai untuk melepaskan sumber daya penghitung waktu.Task
, pengecualian apa pun yang disimpan oleh tugas di-rethrown pada saat itu. Ini memberi Anda kesempatan untuk menangkapOperationCanceledException
(jika dibatalkan) atau pengecualian lainnya (jika salah).Task.Wait(timeout)
akan secara sinkron memblokir bukannya menunggu secara tidak sinkron.Berikut adalah versi metode ekstensi yang menyertakan pembatalan batas waktu ketika tugas asli selesai seperti yang disarankan oleh Andrew Arnott dalam komentar untuk jawabannya .
sumber
using
bloktask.Result
ketika dieksekusi dua kali.task
) masih terus berjalan jika terjadi batas waktu?TimeoutException
memiliki pesan default yang sesuai. Mengatasinya dengan "Operasi telah kehabisan waktu." tidak menambah nilai dan sebenarnya menyebabkan kebingungan dengan menyiratkan ada alasan untuk menimpanya.Anda dapat menggunakan
Task.WaitAny
untuk menunggu yang pertama dari banyak tugas.Anda dapat membuat dua tugas tambahan (yang selesai setelah batas waktu yang ditentukan) dan kemudian gunakan
WaitAny
untuk menunggu mana yang lebih dulu selesai. Jika tugas yang diselesaikan pertama adalah tugas "pekerjaan" Anda, maka Anda selesai. Jika tugas yang diselesaikan pertama adalah tugas batas waktu, maka Anda dapat bereaksi terhadap batas waktu tersebut (mis. Permintaan pembatalan).sumber
below
.... yang itu? berdasarkan pemesanan SO?Bagaimana dengan sesuatu yang seperti ini?
Anda dapat menggunakan opsi Task.Wait tanpa memblokir utas menggunakan Tugas lain.
sumber
Berikut adalah contoh yang berfungsi sepenuhnya berdasarkan jawaban yang dipilih teratas, yaitu:
Keuntungan utama dari implementasi dalam jawaban ini adalah bahwa obat generik telah ditambahkan, sehingga fungsi (atau tugas) dapat mengembalikan nilai. Ini berarti bahwa setiap fungsi yang ada dapat dibungkus dengan fungsi batas waktu, misalnya:
Sebelum:
Setelah:
Kode ini membutuhkan .NET 4.5.
Peringatan
Setelah memberikan jawaban ini, biasanya bukan praktik yang baik untuk memiliki pengecualian yang dimasukkan dalam kode Anda selama operasi normal, kecuali Anda benar-benar harus:
Gunakan hanya kode ini jika Anda benar-benar tidak dapat mengubah fungsi yang Anda panggil sehingga waktu habis setelah spesifik
TimeSpan
.Jawaban ini benar-benar hanya berlaku ketika berhadapan dengan perpustakaan perpustakaan pihak ke-3 yang Anda tidak bisa menolak untuk memasukkan parameter batas waktu.
Cara menulis kode yang kuat
Jika Anda ingin menulis kode yang kuat, aturan umumnya adalah ini:
Jika Anda tidak mematuhi aturan ini, kode Anda pada akhirnya akan mengenai operasi yang gagal karena suatu alasan, maka itu akan diblokir tanpa batas waktu, dan aplikasi Anda baru saja digantung secara permanen.
Jika ada batas waktu yang wajar setelah beberapa waktu, maka aplikasi Anda akan hang selama beberapa waktu yang ekstrem (misalnya 30 detik) maka ia akan menampilkan kesalahan dan melanjutkan dengan cara riang, atau coba lagi.
sumber
Menggunakan pustaka AsyncEx Stephen Cleary yang sangat baik , Anda dapat melakukan:
TaskCanceledException
akan dilemparkan jika terjadi timeout.sumber
Ini adalah versi yang sedikit lebih baik dari jawaban sebelumnya.
CancellationToken
untuk tugas asli, dan ketika batas waktu terjadi, Anda mendapatkanTimeoutException
alih-alihOperationCanceledException
.Pemakaian
InnerCallAsync
mungkin butuh waktu lama untuk selesai.CallAsync
membungkusnya dengan batas waktu.sumber
timeoutCancellation
masukdelayTask
. Saat ini, jika Anda memecat pembatalan,CancelAfterAsync
bisa melemparTimeoutException
bukanTaskCanceledException
, sebabdelayTask
mungkin selesai dulu.WhenAny
dibatalkan dengan token yang sama,WhenAny
akan mengembalikan tugas pertama. Asumsi itu salah. Saya sudah mengedit jawabannya. Terima kasih!Gunakan Timer untuk menangani pesan dan pembatalan otomatis. Saat Tugas selesai, hubungi Buang penghitung waktu agar mereka tidak akan pernah menyala. Berikut ini sebuah contoh; ubah taskDelay menjadi 500, 1500, atau 2500 untuk melihat berbagai kasus:
Juga, CTP Async menyediakan metode TaskEx.Delay yang akan membungkus pengatur waktu dalam tugas untuk Anda. Ini dapat memberi Anda lebih banyak kontrol untuk melakukan hal-hal seperti mengatur TaskScheduler untuk kelanjutan ketika Timer menyala.
sumber
task.Wait()
.Cara lain untuk memecahkan masalah ini adalah menggunakan Ekstensi Reaktif:
Uji di atas menggunakan kode di bawah ini dalam unit test Anda, itu berfungsi untuk saya
Anda mungkin memerlukan namespace berikut:
sumber
Versi generik jawaban @ Kevan di atas, menggunakan Ekstensi Reaktif.
Dengan Penjadwal opsional:
BTW: Ketika Timeout terjadi, eksepsi timeout akan dilempar
sumber
Jika Anda menggunakan BlockingCollection untuk menjadwalkan tugas, produsen dapat menjalankan tugas yang berpotensi berjalan lama dan konsumen dapat menggunakan metode TryTake yang memiliki batas waktu dan token pembatalan bawaan.
sumber
Saya merasakan
Task.Delay()
tugas danCancellationTokenSource
jawaban lain sedikit banyak untuk kasus penggunaan saya dalam loop jaringan yang ketat.Dan meskipun begitu Joe Hoag's Crafting a Task.TimeoutSetelah Metode di blog MSDN menginspirasi, saya sedikit lelah menggunakan
TimeoutException
untuk kontrol aliran untuk alasan yang sama seperti di atas, karena timeout diharapkan lebih sering daripada tidak.Jadi saya pergi dengan ini, yang juga menangani optimasi yang disebutkan di blog:
Contoh use case adalah sebagai berikut:
sumber
Beberapa varian jawaban Andrew Arnott:
Jika Anda ingin menunggu tugas yang ada dan mencari tahu apakah tugasnya selesai atau waktunya habis, tetapi tidak ingin membatalkannya jika batas waktu terjadi:
Jika Anda ingin memulai tugas kerja dan membatalkan pekerjaan jika batas waktu terjadi:
Jika Anda memiliki tugas yang sudah dibuat yang ingin Anda batalkan jika terjadi timeout:
Komentar lain, versi ini akan membatalkan timer jika batas waktu tidak terjadi, sehingga beberapa panggilan tidak akan menyebabkan timer menumpuk.
sjb
sumber
Saya menggabungkan ide-ide dari beberapa jawaban lain di sini dan jawaban ini di utas lain menjadi metode ekstensi gaya Try. Ini memiliki manfaat jika Anda menginginkan metode ekstensi, namun menghindari pengecualian pada batas waktu.
sumber
Jelas tidak melakukan ini, tetapi itu adalah pilihan jika ... Saya tidak bisa memikirkan alasan yang sah.
sumber