แค่นี้ - คุณจะเพิ่มตัวจับเวลาลงในแอปพลิเคชันคอนโซล C # ได้อย่างไร? จะดีมากถ้าคุณสามารถจัดหาตัวอย่างการเข้ารหัสได้
แค่นี้ - คุณจะเพิ่มตัวจับเวลาลงในแอปพลิเคชันคอนโซล C # ได้อย่างไร? จะดีมากถ้าคุณสามารถจัดหาตัวอย่างการเข้ารหัสได้
คำตอบ:
เป็นเรื่องที่ดีมากอย่างไรก็ตามในการจำลองเวลาที่ผ่านไปเราจำเป็นต้องเรียกใช้คำสั่งที่ใช้เวลาพอสมควรและชัดเจนมากในตัวอย่างที่สอง
อย่างไรก็ตามรูปแบบของการใช้ for loop เพื่อทำงานบางอย่างตลอดไปนั้นใช้ทรัพยากรอุปกรณ์จำนวนมากและเราสามารถใช้ Garbage Collector เพื่อทำบางสิ่งเช่นนั้นแทนได้
เราสามารถดูการแก้ไขนี้ได้ในโค้ดจากหนังสือเล่มเดียวกัน CLR ผ่าน C # Third Ed
using System;
using System.Threading;
public static class Program {
public static void Main() {
// Create a Timer object that knows to call our TimerCallback
// method once every 2000 milliseconds.
Timer t = new Timer(TimerCallback, null, 0, 2000);
// Wait for the user to hit <Enter>
Console.ReadLine();
}
private static void TimerCallback(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();
}
}
GC.Collect()
ฉันไม่เห็นจุดของการโทร ไม่มีอะไรให้เก็บสะสม มันจะสมเหตุสมผลถ้าGC.KeepAlive(t)
ถูกเรียกหลังConsole.ReadLine();
ใช้คลาส System.Threading.Timer
System.Windows.Forms.Timer ได้รับการออกแบบมาเพื่อใช้ในเธรดเดียวโดยปกติจะเป็นเธรด UI ของ Windows Forms
นอกจากนี้ยังมีคลาส System.Timers ที่เพิ่มเข้ามาในช่วงต้นของการพัฒนา. NET framework อย่างไรก็ตามโดยทั่วไปแนะนำให้ใช้คลาส System.Threading.Timer แทนเนื่องจากนี่เป็นเพียง wrapper รอบ ๆ System.Threading.Timer เท่านั้น
ขอแนะนำให้ใช้ระบบแบบคงที่ (แชร์ใน VB.NET) เสมอตัวตั้งเวลาหากคุณกำลังพัฒนาบริการ Windows และต้องใช้ตัวจับเวลาเพื่อให้ทำงานเป็นระยะ วิธีนี้จะหลีกเลี่ยงการเก็บขยะวัตถุจับเวลาของคุณก่อนเวลาอันควร
นี่คือตัวอย่างของตัวจับเวลาในแอปพลิเคชันคอนโซล:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
Console.WriteLine("Main thread: starting a timer");
Timer t = new Timer(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 delegate
private static void ComputeBoundOp(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
}
}
จากหนังสือCLR Via C #โดย Jeff Richter หนังสือเล่มนี้อธิบายถึงเหตุผลเบื้องหลังตัวจับเวลา 3 ประเภทในบทที่ 23 ขอแนะนำ
นี่คือรหัสสำหรับสร้างเครื่องหมายจับเวลาหนึ่งวินาทีอย่างง่าย:
using System;
using System.Threading;
class TimerExample
{
static public void Tick(Object stateInfo)
{
Console.WriteLine("Tick: {0}", DateTime.Now.ToString("h:mm:ss"));
}
static void Main()
{
TimerCallback callback = new TimerCallback(Tick);
Console.WriteLine("Creating timer: {0}\n",
DateTime.Now.ToString("h:mm:ss"));
// create a one second timer tick
Timer stateTimer = new Timer(callback, null, 0, 1000);
// loop here forever
for (; ; )
{
// add a sleep for 100 mSec to reduce CPU usage
Thread.Sleep(100);
}
}
}
และนี่คือผลลัพธ์ที่ได้:
c:\temp>timer.exe
Creating timer: 5:22:40
Tick: 5:22:40
Tick: 5:22:41
Tick: 5:22:42
Tick: 5:22:43
Tick: 5:22:44
Tick: 5:22:45
Tick: 5:22:46
Tick: 5:22:47
แก้ไข:ไม่ควรเพิ่มฮาร์ดสปินลูปลงในโค้ดเนื่องจากใช้รอบ CPU โดยไม่ได้รับ ในกรณีนี้มีการเพิ่มลูปเพียงเพื่อหยุดแอปพลิเคชันจากการปิดทำให้สามารถสังเกตการทำงานของเธรดได้ แต่เพื่อความถูกต้องและเพื่อลดการใช้งาน CPU จึงมีการเพิ่ม Sleep call แบบธรรมดาลงในลูปนั้น
มาสนุกกันเถอะ
using System;
using System.Timers;
namespace TimerExample
{
class Program
{
static Timer timer = new Timer(1000);
static int i = 10;
static void Main(string[] args)
{
timer.Elapsed+=timer_Elapsed;
timer.Start(); Console.Read();
}
private static void 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();
}
}
}
หรือใช้ Rx สั้นและหวาน:
static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));
for (; ; ) { }
}
คุณยังสามารถใช้กลไกการจับเวลาของคุณเองได้หากคุณต้องการการควบคุมที่มากขึ้นเล็กน้อย แต่อาจมีความแม่นยำน้อยลงและมีรหัส / ความซับซ้อนมากขึ้น แต่ฉันยังคงแนะนำตัวจับเวลา ใช้สิ่งนี้แม้ว่าคุณต้องการควบคุมเธรดเวลาจริง:
private void ThreadLoop(object callback)
{
while(true)
{
((Delegate) callback).DynamicInvoke(null);
Thread.Sleep(5000);
}
}
จะเป็นเธรดการกำหนดเวลาของคุณ (แก้ไขสิ่งนี้เพื่อหยุดเมื่อมีการร้องขอและในช่วงเวลาใดก็ตามที่คุณต้องการ)
และในการใช้ / เริ่มคุณสามารถทำได้:
Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));
t.Start((Action)CallBack);
การโทรกลับเป็นวิธีที่ไม่มีพารามิเตอร์เป็นโมฆะของคุณที่คุณต้องการเรียกใช้ในแต่ละช่วงเวลา ตัวอย่างเช่น:
private void CallBack()
{
//Do Something.
}
คุณยังสามารถสร้างของคุณเองได้ (หากไม่พอใจกับตัวเลือกที่มีให้)
การสร้างการTimer
ใช้งานของคุณเองเป็นเรื่องพื้นฐาน
นี่คือตัวอย่างสำหรับแอปพลิเคชันที่ต้องการการเข้าถึงวัตถุ COM บนเธรดเดียวกับส่วนที่เหลือของ codebase ของฉัน
/// <summary>
/// Internal timer for window.setTimeout() and window.setInterval().
/// This is to ensure that async calls always run on the same thread.
/// </summary>
public class Timer : IDisposable {
public void Tick()
{
if (Enabled && Environment.TickCount >= nextTick)
{
Callback.Invoke(this, null);
nextTick = Environment.TickCount + Interval;
}
}
private int nextTick = 0;
public void Start()
{
this.Enabled = true;
Interval = interval;
}
public void Stop()
{
this.Enabled = false;
}
public event EventHandler Callback;
public bool Enabled = false;
private int interval = 1000;
public int Interval
{
get { return interval; }
set { interval = value; nextTick = Environment.TickCount + interval; }
}
public void Dispose()
{
this.Callback = null;
this.Stop();
}
}
คุณสามารถเพิ่มเหตุการณ์ได้ดังนี้:
Timer timer = new Timer();
timer.Callback += delegate
{
if (once) { timer.Enabled = false; }
Callback.execute(callbackId, args);
};
timer.Enabled = true;
timer.Interval = ms;
timer.Start();
Window.timers.Add(Environment.TickCount, timer);
เพื่อให้แน่ใจว่าตัวจับเวลาทำงานคุณต้องสร้างลูปที่ไม่มีที่สิ้นสุดดังนี้:
while (true) {
// Create a new list in case a new timer
// is added/removed during a callback.
foreach (Timer timer in new List<Timer>(timers.Values))
{
timer.Tick();
}
}
ใน C # 5.0+ และ. NET Framework 4.5+ คุณสามารถใช้ async / await:
async void RunMethodEvery(Action method, double seconds)
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(seconds));
method();
}
}
คุณมีมัน :)
public static void Main()
{
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...");
}
private static void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
ฉันขอแนะนำให้คุณปฏิบัติตามแนวทางของ Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 )
ฉันลองใช้ครั้งแรกSystem.Threading;
กับ
var myTimer = new Timer((e) =>
{
// Code
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
แต่มันหยุดลงอย่างต่อเนื่องหลังจากผ่านไปประมาณ 20 นาที
ด้วยเหตุนี้ฉันจึงลองตั้งค่าโซลูชัน
GC.KeepAlive(myTimer)
หรือ
for (; ; ) { }
}
แต่ไม่ได้ผลในกรณีของฉัน
ตามเอกสารของ Microsoft มันทำงานได้อย่างสมบูรณ์:
using System;
using System.Timers;
public class Example
{
private static Timer aTimer;
public static void Main()
{
// Create a timer and set a two second interval.
aTimer = new System.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();
}
private static void OnTimedEvent(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