Perhatian: jawaban di sini memiliki bug, objek Timer akan mengumpulkan sampah. Referensi ke timer harus disimpan dalam variabel statis untuk memastikannya terus berdetak.
Hans Passant
@HansPassant Anda sepertinya telah melewatkan pernyataan yang jelas dalam jawaban saya: "Juga disarankan untuk selalu menggunakan sistem statis (dibagi dalam VB.NET). Memulai. Jika Anda sedang mengembangkan Layanan Windows dan memerlukan timer untuk berjalan secara berkala Ini akan menghindari kemungkinan pengumpulan sampah prematur dari objek pengatur waktu Anda. " Jika orang ingin menyalin contoh acak dan menggunakannya secara membabi buta itu masalah mereka.
Ash
Jawaban:
120
Itu sangat bagus, namun untuk mensimulasikan beberapa waktu yang berlalu kita perlu menjalankan perintah yang membutuhkan waktu dan itu sangat jelas dalam contoh kedua.
Namun, gaya menggunakan loop untuk melakukan beberapa fungsi selamanya membutuhkan banyak sumber daya perangkat dan sebagai gantinya kita dapat menggunakan Pengumpul Sampah untuk melakukan hal seperti itu.
Kita dapat melihat modifikasi ini dalam kode dari buku yang sama CLR Via C # Third Ed.
using System;
using System.Threading;publicstaticclassProgram{publicstaticvoidMain(){// Create a Timer object that knows to call our TimerCallback// method once every 2000 milliseconds.Timer t =newTimer(TimerCallback,null,0,2000);// Wait for the user to hit <Enter>Console.ReadLine();}privatestaticvoidTimerCallback(Object o){// Display the date/time when this method got called.Console.WriteLine("In TimerCallback: "+DateTime.Now);// Force a garbage collection to occur for this demo.
GC.Collect();}}
Khalid, ini sangat membantu. Terima kasih. The console.readline () dan GC.Collect adalah apa yang saya butuhkan.
Seth Spearman
9
@Ralph Willgoss, Why GC.Collect (); diperlukan?
Puchacz
2
@ Puchacz Saya tidak melihat titik menelepon GC.Collect(). Tidak ada yang dikumpulkan. Akan masuk akal, jika GC.KeepAlive(t)dipanggil setelahConsole.ReadLine();
cetak baru
1
Itu dihentikan setelah panggilan balik pertama
BadPiggie
1
@Khalid Al Hajami "Namun, gaya menggunakan loop for untuk melakukan fungsionalitas selamanya membutuhkan banyak sumber daya perangkat dan sebagai gantinya kita dapat menggunakan Pengumpul Sampah untuk melakukan hal-hal seperti itu." Ini benar-benar sampah yang tidak masuk akal. Pengumpul sampah sama sekali tidak relevan. Apakah Anda menyalin ini dari buku dan tidak mengerti apa yang Anda salin?
Ash
65
Gunakan kelas System.Threading.Timer.
System.Windows.Forms.Timer dirancang terutama untuk digunakan dalam utas tunggal biasanya utas Windows Forms UI.
Ada juga kelas System.Timers ditambahkan sejak awal dalam pengembangan kerangka NET. Namun umumnya disarankan untuk menggunakan kelas System.Threading.Timer sebagai gantinya ini hanya pembungkus di sekitar System.Threading.Timer saja.
Dianjurkan juga untuk selalu menggunakan Sistem statis (dibagi dalam VB.NET) System.Threading.Timer jika Anda mengembangkan Layanan Windows dan memerlukan timer untuk berjalan secara berkala. Ini akan menghindari kemungkinan pengumpulan sampah prematur dari objek pengatur waktu Anda.
Berikut ini contoh penghitung waktu di aplikasi konsol:
using System;
using System.Threading;publicstaticclassProgram{publicstaticvoidMain(){Console.WriteLine("Main thread: starting a timer");Timer t =newTimer(ComputeBoundOp,5,0,2000);Console.WriteLine("Main thread: Doing other work here...");Thread.Sleep(10000);// Simulating other work (10 seconds)
t.Dispose();// Cancel the timer now}// This method's signature must match the TimerCallback delegateprivatestaticvoidComputeBoundOp(Object state){// This method is executed by a thread pool thread Console.WriteLine("In ComputeBoundOp: state={0}", state);Thread.Sleep(1000);// Simulates other work (1 second)// When this method returns, the thread goes back // to the pool and waits for another task }}
Dari buku CLR Via C # oleh Jeff Richter. Ngomong-ngomong buku ini menggambarkan alasan di balik 3 jenis penghitung waktu di Bab 23, sangat dianjurkan.
Eric, saya belum mencobanya tetapi tidak aneh jika ada masalah dengan itu. Saya perhatikan itu juga mencoba melakukan semacam sinkronisasi antar-thread, ini selalu merupakan area yang sulit untuk dilakukan dengan benar. Jika Anda dapat menghindarinya dalam desain Anda, itu selalu pintar untuk melakukannya.
Ash
1
Ash - Saya pasti setuju tentang contoh msdn. Saya tidak akan segera mengabaikan kode sinkronisasi, jika timer berjalan di utasnya sendiri, maka Anda menulis aplikasi multi-utas dan perlu mengetahui masalah yang berkaitan dengan sinkronisasi.
Eric Tuttleman
1
Apa yang terjadi jika ada beberapa metode yang cocok dengan tanda tangan delegasi TimerCallback?
Ozkan
22
Berikut adalah kode untuk membuat centang satu detik sederhana:
using System;
using System.Threading;classTimerExample{staticpublicvoidTick(Object stateInfo){Console.WriteLine("Tick: {0}",DateTime.Now.ToString("h:mm:ss"));}staticvoidMain(){TimerCallback callback =newTimerCallback(Tick);Console.WriteLine("Creating timer: {0}\n",DateTime.Now.ToString("h:mm:ss"));// create a one second timer tickTimer stateTimer =newTimer(callback,null,0,1000);// loop here foreverfor(;;){// add a sleep for 100 mSec to reduce CPU usageThread.Sleep(100);}}}
EDIT: Tidak pernah merupakan ide yang baik untuk menambahkan hard spin loop ke dalam kode karena mereka mengkonsumsi siklus CPU tanpa hasil. Dalam hal ini, loop ditambahkan hanya untuk menghentikan aplikasi agar tidak menutup, sehingga tindakan dari thread dapat diamati. Tetapi demi kebenaran dan untuk mengurangi penggunaan CPU panggilan Sleep sederhana telah ditambahkan ke loop itu.
Bukankah sudah cukup jelas jika Anda memiliki infinite untuk loop maka itu akan menghasilkan CPU 100%. Untuk memperbaikinya yang perlu Anda lakukan adalah menambahkan panggilan tidur ke loop.
veight
3
Sungguh menakjubkan berapa banyak orang yang terpaku pada apakah for loop harus sementara dan mengapa CPU mencapai 100%. Bicara tentang merindukan kayu untuk pohon! Azimuth, saya pribadi ingin tahu bagaimana beberapa saat (1) akan berbeda dengan infinite untuk loop? Tentunya orang-orang yang menulis optimizer kompiler CLR akan memastikan dua konstruksi kode ini membuat kode CLR yang sama persis?
Blake7
1
Salah satu alasan mengapa sementara (1) tidak berfungsi adalah tidak valid c #: test.cs (21,20): error CS0031: Nilai konstan '1' tidak dapat dikonversi ke 'bool'
Blake7
1
Tidak di komputer saya (win8.1, i5), hanya sekitar 20-30%, komputer seperti apa yang Anda miliki saat itu? @SethSpearman
shinzou
17
Mari Bersenang-senang
using System;
using System.Timers;
namespace TimerExample{classProgram{staticTimer timer =newTimer(1000);staticint i =10;staticvoidMain(string[] args){
timer.Elapsed+=timer_Elapsed;
timer.Start();Console.Read();}privatestaticvoid timer_Elapsed(object sender,ElapsedEventArgs e){
i--;Console.Clear();Console.WriteLine("=================================================");Console.WriteLine(" DEFUSE THE BOMB");Console.WriteLine("");Console.WriteLine(" Time Remaining: "+ i.ToString());Console.WriteLine("");Console.WriteLine("=================================================");if(i ==0){Console.Clear();Console.WriteLine("");Console.WriteLine("==============================================");Console.WriteLine(" B O O O O O M M M M M ! ! ! !");Console.WriteLine("");Console.WriteLine(" G A M E O V E R");Console.WriteLine("==============================================");
timer.Close();
timer.Dispose();}
GC.Collect();}}}
sangat tidak dapat dibaca dan bertentangan dengan praktik terbaik. Itu terlihat luar biasa tetapi tidak boleh digunakan dalam produksi karena beberapa ppl akan pergi wtf dan buang air besar sendiri.
Piotr Kula
2
Ekstensi Reaktif (Rx) belum aktif dikembangkan selama 2 tahun. Selain itu contoh-contohnya tanpa konteks dan membingungkan. Sedikit tahu diagram atau contoh mengalir.
James Bailey
4
Anda juga dapat menggunakan mekanisme pengaturan waktu Anda sendiri jika Anda ingin sedikit lebih banyak kontrol, tetapi mungkin kurang akurat dan lebih banyak kode / kompleksitas, tetapi saya masih akan merekomendasikan timer. Gunakan ini meskipun jika Anda harus memiliki kontrol atas utas waktu aktual:
Jika saya ingin menjalankan pekerjaan batch sampai habis, akankah saran Anda di sini menjadi yang terbaik?
Johan Bresler
1
Anda juga dapat membuat sendiri (jika tidak puas dengan opsi yang tersedia).
Membuat Timerimplementasi Anda sendiri adalah hal yang cukup mendasar.
Ini adalah contoh untuk aplikasi yang membutuhkan akses objek COM pada utas yang sama dengan sisa basis kode saya.
/// <summary>/// Internal timer for window.setTimeout() and window.setInterval()./// This is to ensure that async calls always run on the same thread./// </summary>publicclassTimer:IDisposable{publicvoidTick(){if(Enabled&&Environment.TickCount>= nextTick){Callback.Invoke(this,null);
nextTick =Environment.TickCount+Interval;}}privateint nextTick =0;publicvoidStart(){this.Enabled=true;Interval= interval;}publicvoidStop(){this.Enabled=false;}publiceventEventHandlerCallback;publicboolEnabled=false;privateint interval =1000;publicintInterval{get{return interval;}set{ interval =value; nextTick =Environment.TickCount+ interval;}}publicvoidDispose(){this.Callback=null;this.Stop();}}
Untuk memastikan timer berfungsi, Anda perlu membuat loop tanpa akhir sebagai berikut:
while(true){// Create a new list in case a new timer// is added/removed during a callback.foreach(Timer timer innewList<Timer>(timers.Values)){
timer.Tick();}}
publicstaticvoidMain(){SetTimer();Console.WriteLine("\nPress the Enter key to exit the application...\n");Console.WriteLine("The application started at {0:HH:mm:ss.fff}",DateTime.Now);Console.ReadLine();
aTimer.Stop();
aTimer.Dispose();Console.WriteLine("Terminating the application...");}privatestaticvoidSetTimer(){// Create a timer with a two second interval.
aTimer =newSystem.Timers.Timer(2000);// Hook up the Elapsed event for the timer.
aTimer.Elapsed+=OnTimedEvent;
aTimer.AutoReset=true;
aTimer.Enabled=true;}privatestaticvoidOnTimedEvent(Object source,ElapsedEventArgs e){Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);}
Saya pertama kali mencoba menggunakan System.Threading;dengan
var myTimer =newTimer((e)=>{// Code},null,TimeSpan.Zero,TimeSpan.FromSeconds(5));
tetapi terus berhenti setelah ~ 20 menit.
Dengan itu, saya mencoba pengaturan solusi
GC.KeepAlive(myTimer)
atau
for(;;){}}
tetapi mereka tidak bekerja dalam kasus saya.
Berikut dokumentasi Microsoft, ini bekerja dengan sempurna:
using System;
using System.Timers;publicclassExample{privatestaticTimer aTimer;publicstaticvoidMain(){// Create a timer and set a two second interval.
aTimer =newSystem.Timers.Timer();
aTimer.Interval=2000;// Hook up the Elapsed event for the timer.
aTimer.Elapsed+=OnTimedEvent;// Have the timer fire repeated events (true is the default)
aTimer.AutoReset=true;// Start the timer
aTimer.Enabled=true;Console.WriteLine("Press the Enter key to exit the program at any time... ");Console.ReadLine();}privatestaticvoidOnTimedEvent(Object source,System.Timers.ElapsedEventArgs e){Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);}}// The example displays output like the following: // Press the Enter key to exit the program at any time... // The Elapsed event was raised at 5/20/2015 8:48:58 PM // The Elapsed event was raised at 5/20/2015 8:49:00 PM // The Elapsed event was raised at 5/20/2015 8:49:02 PM // The Elapsed event was raised at 5/20/2015 8:49:04 PM // The Elapsed event was raised at 5/20/2015 8:49:06 PM
Jawaban:
Itu sangat bagus, namun untuk mensimulasikan beberapa waktu yang berlalu kita perlu menjalankan perintah yang membutuhkan waktu dan itu sangat jelas dalam contoh kedua.
Namun, gaya menggunakan loop untuk melakukan beberapa fungsi selamanya membutuhkan banyak sumber daya perangkat dan sebagai gantinya kita dapat menggunakan Pengumpul Sampah untuk melakukan hal seperti itu.
Kita dapat melihat modifikasi ini dalam kode dari buku yang sama CLR Via C # Third Ed.
sumber
GC.Collect()
. Tidak ada yang dikumpulkan. Akan masuk akal, jikaGC.KeepAlive(t)
dipanggil setelahConsole.ReadLine();
Gunakan kelas System.Threading.Timer.
System.Windows.Forms.Timer dirancang terutama untuk digunakan dalam utas tunggal biasanya utas Windows Forms UI.
Ada juga kelas System.Timers ditambahkan sejak awal dalam pengembangan kerangka NET. Namun umumnya disarankan untuk menggunakan kelas System.Threading.Timer sebagai gantinya ini hanya pembungkus di sekitar System.Threading.Timer saja.
Dianjurkan juga untuk selalu menggunakan Sistem statis (dibagi dalam VB.NET) System.Threading.Timer jika Anda mengembangkan Layanan Windows dan memerlukan timer untuk berjalan secara berkala. Ini akan menghindari kemungkinan pengumpulan sampah prematur dari objek pengatur waktu Anda.
Berikut ini contoh penghitung waktu di aplikasi konsol:
Dari buku CLR Via C # oleh Jeff Richter. Ngomong-ngomong buku ini menggambarkan alasan di balik 3 jenis penghitung waktu di Bab 23, sangat dianjurkan.
sumber
Berikut adalah kode untuk membuat centang satu detik sederhana:
Dan inilah output yang dihasilkan:
EDIT: Tidak pernah merupakan ide yang baik untuk menambahkan hard spin loop ke dalam kode karena mereka mengkonsumsi siklus CPU tanpa hasil. Dalam hal ini, loop ditambahkan hanya untuk menghentikan aplikasi agar tidak menutup, sehingga tindakan dari thread dapat diamati. Tetapi demi kebenaran dan untuk mengurangi penggunaan CPU panggilan Sleep sederhana telah ditambahkan ke loop itu.
sumber
Mari Bersenang-senang
sumber
Atau menggunakan Rx, pendek dan manis:
sumber
Anda juga dapat menggunakan mekanisme pengaturan waktu Anda sendiri jika Anda ingin sedikit lebih banyak kontrol, tetapi mungkin kurang akurat dan lebih banyak kode / kompleksitas, tetapi saya masih akan merekomendasikan timer. Gunakan ini meskipun jika Anda harus memiliki kontrol atas utas waktu aktual:
akan menjadi utas waktu Anda (modifikasi ini untuk berhenti ketika diperlukan, dan pada interval waktu apa pun yang Anda inginkan).
dan untuk menggunakan / memulai Anda dapat melakukan:
Callback adalah metode tanpa parameter kosong yang ingin Anda panggil pada setiap interval. Sebagai contoh:
sumber
Anda juga dapat membuat sendiri (jika tidak puas dengan opsi yang tersedia).
Membuat
Timer
implementasi Anda sendiri adalah hal yang cukup mendasar.Ini adalah contoh untuk aplikasi yang membutuhkan akses objek COM pada utas yang sama dengan sisa basis kode saya.
Anda dapat menambahkan acara sebagai berikut:
Untuk memastikan timer berfungsi, Anda perlu membuat loop tanpa akhir sebagai berikut:
sumber
Dalam C # 5.0+ dan .NET Framework 4.5+ Anda dapat menggunakan async / menunggu:
sumber
dokter
Itu dia :)
sumber
Saya sarankan Anda mengikuti pedoman Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ).
Saya pertama kali mencoba menggunakan
System.Threading;
dengantetapi terus berhenti setelah ~ 20 menit.
Dengan itu, saya mencoba pengaturan solusi
atau
tetapi mereka tidak bekerja dalam kasus saya.
Berikut dokumentasi Microsoft, ini bekerja dengan sempurna:
sumber