c# 實作根據時間串列 依次精準 穩定 執行事件? 精度1ms ?
我用Stopwatch時鐘 , 有時候會誤差到 20ms。
List<int> timeList = new List<int>();
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < timeList.Count; i++)
{
while (watch.ElapsedMilliseconds < timeList[i])
{
}
//事件 --不考慮事件未執行完,時間就超過下次時鐘。
}
還有其他執行緒影響。。
uj5u.com熱心網友回復:
可考慮使用異步
uj5u.com熱心網友回復:
static async void test()
{
List<int> timeList = new List<int>() { 2, 4, 6, 8 };
Console.WriteLine($"當前時間:{DateTime.Now}");
foreach (var item in timeList)
{
Task t = Task.Run(async () =>
{
await Task.Delay(item * 1000);
Console.WriteLine(DateTime.Now + $":{item}秒后執行輸出:{item}");
});
await t;
}
}
uj5u.com熱心網友回復:
參考 2 樓 殺馬特丶蠻牛 的回復:
static async void test()
{
List<int> timeList = new List<int>() { 2, 4, 6, 8 };
Console.WriteLine($"當前時間:{DateTime.Now}");
foreach (var item in timeList)
{
Task t = Task.Run(async () =>
{
await Task.Delay(item * 1000);
Console.WriteLine(DateTime.Now + $":{item}秒后執行輸出:{item}");
});
await t;
}
}
參考 2 樓 殺馬特丶蠻牛 的回復:
static async void test()
{
List<int> timeList = new List<int>() { 2, 4, 6, 8 };
Console.WriteLine($"當前時間:{DateTime.Now}");
foreach (var item in timeList)
{
Task t = Task.Run(async () =>
{
await Task.Delay(item * 1000);
Console.WriteLine(DateTime.Now + $":{item}秒后執行輸出:{item}");
});
await t;
}
}
并不是很精準。
uj5u.com熱心網友回復:
還有其他方法 嗎?
uj5u.com熱心網友回復:
如果實時操作是硬要求(比如輸變電控制),那么你不能用C#,甚至Windows系統也不合適。
因為C#不支持實時操作,Windows系統也
不是實時作業系統 。
uj5u.com熱心網友回復:
參考 5 樓 github_36000833 的回復: ...因為C#不支持實時操作...
用詞更準確的說,Dotnet CLR不支持實時操作。比如垃圾回收本身就是不確定的,而且會掛起執行緒,比如Task調度是不確定的等等。
uj5u.com熱心網友回復:
試試用異步執行緒定時器, System.Threading.Timer
uj5u.com熱心網友回復:
1ms? 不可能,干嘛要這么精確?除非你加硬體設備,外部時鐘定時觸發,然后你寫個設備驅動,在驅動里處理
uj5u.com熱心網友回復:
你換系統吧
uj5u.com熱心網友回復:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
namespace HighTimer
{
public class TimerEventArgs : EventArgs
{
private long clockFrequency;
public long ClockFrequency
{
get { return clockFrequency; }
}
private long previousTickCount;
public long PreviousTickOunt
{
get { return previousTickCount; }
}
private long currentTickCount;
public long CurrentTickCount
{
get { return currentTickCount; }
}
public TimerEventArgs(long clockFreq, long prevTick, long currTick)
{
this.clockFrequency = clockFreq;
this.previousTickCount = prevTick;
this.currentTickCount = currTick;
}
}
/// <summary>
/// 高精度定時器事件委托
/// </summary>
public delegate void HighTimerEventHandler(object sender,TimerEventArgs e);
public class HighAccurateTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
public event HighTimerEventHandler Elapsed;
Thread thread;
private object threadLock = new object();
private long clockFrequency = 0;
private long intevalTicks = 0;
private long nextTriggerTime = 0;
private int intervalMs;
/// <summary>
/// 定時器間隔
/// </summary>
public int Interval
{
get
{
return intervalMs;
}
set
{
intervalMs = value;
}
}
private bool enable;
/// <summary>
/// 啟動定時器標志
/// </summary>
public bool Enabled
{
get
{
return enable;
}
set
{
enable = value;
if (value == true)
{
intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
long currTick = 0;
GetTick(out currTick);
nextTriggerTime = currTick + intevalTicks;
}
}
}
/// <summary>
/// 建構式
/// </summary>
public HighAccurateTimer()
{
if (QueryPerformanceFrequency(out clockFrequency) == false)
{
return;
}
this.intervalMs = 1000;
this.enable = false;
thread = new Thread(new ThreadStart(ThreadProc));
thread.Name = "HighAccuracyTimer";
thread.Priority = ThreadPriority.Highest;
thread.Start();
}
/// <summary>
/// 行程主程式
/// </summary>
private void ThreadProc()
{
long currTime;
GetTick(out currTime);
nextTriggerTime = currTime + intevalTicks;
while (true)
{
while (currTime < nextTriggerTime)
{
GetTick(out currTime); //決定時鐘的精度
}
nextTriggerTime = currTime + intevalTicks;
if (Elapsed != null && enable == true)
{
Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
}
}
}
/// <summary>
/// 獲得當前時鐘計數
/// </summary>
/// <param name="currentTickCount">時鐘計數</param>
/// <returns>獲得是否成功</returns>
public bool GetTick(out long currentTickCount)
{
if (QueryPerformanceCounter(out currentTickCount) == false)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 注銷定時器
/// </summary>
public void Destroy()
{
enable = false;
thread.Abort();
}
}
}
uj5u.com熱心網友回復:
參考 10 樓 xuzuning 的回復: using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
namespace HighTimer
{
public class TimerEventArgs : EventArgs
{
private long clockFrequency;
public long ClockFrequency
{
get { return clockFrequency; }
}
private long previousTickCount;
public long PreviousTickOunt
{
get { return previousTickCount; }
}
private long currentTickCount;
public long CurrentTickCount
{
get { return currentTickCount; }
}
public TimerEventArgs(long clockFreq, long prevTick, long currTick)
{
this.clockFrequency = clockFreq;
this.previousTickCount = prevTick;
this.currentTickCount = currTick;
}
}
/// <summary>
/// 高精度定時器事件委托
/// </summary>
public delegate void HighTimerEventHandler(object sender,TimerEventArgs e);
public class HighAccurateTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
public event HighTimerEventHandler Elapsed;
Thread thread;
private object threadLock = new object();
private long clockFrequency = 0;
private long intevalTicks = 0;
private long nextTriggerTime = 0;
private int intervalMs;
/// <summary>
/// 定時器間隔
/// </summary>
public int Interval
{
get
{
return intervalMs;
}
set
{
intervalMs = value;
}
}
private bool enable;
/// <summary>
/// 啟動定時器標志
/// </summary>
public bool Enabled
{
get
{
return enable;
}
set
{
enable = value;
if (value == true)
{
intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
long currTick = 0;
GetTick(out currTick);
nextTriggerTime = currTick + intevalTicks;
}
}
}
/// <summary>
/// 建構式
/// </summary>
public HighAccurateTimer()
{
if (QueryPerformanceFrequency(out clockFrequency) == false)
{
return;
}
this.intervalMs = 1000;
this.enable = false;
thread = new Thread(new ThreadStart(ThreadProc));
thread.Name = "HighAccuracyTimer";
thread.Priority = ThreadPriority.Highest;
thread.Start();
}
/// <summary>
/// 行程主程式
/// </summary>
private void ThreadProc()
{
long currTime;
GetTick(out currTime);
nextTriggerTime = currTime + intevalTicks;
while (true)
{
while (currTime < nextTriggerTime)
{
GetTick(out currTime); //決定時鐘的精度
}
nextTriggerTime = currTime + intevalTicks;
if (Elapsed != null && enable == true)
{
Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
}
}
}
/// <summary>
/// 獲得當前時鐘計數
/// </summary>
/// <param name="currentTickCount">時鐘計數</param>
/// <returns>獲得是否成功</returns>
public bool GetTick(out long currentTickCount)
{
if (QueryPerformanceCounter(out currentTickCount) == false)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 注銷定時器
/// </summary>
public void Destroy()
{
enable = false;
thread.Abort();
}
}
}
這個方法做的計時器我也用過,不太穩定。
uj5u.com熱心網友回復:
參考 11 樓 MichaelGLX 的回復: Quote: 參考 10 樓 xuzuning 的回復: using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
namespace HighTimer
{
public class TimerEventArgs : EventArgs
{
private long clockFrequency;
public long ClockFrequency
{
get { return clockFrequency; }
}
private long previousTickCount;
public long PreviousTickOunt
{
get { return previousTickCount; }
}
private long currentTickCount;
public long CurrentTickCount
{
get { return currentTickCount; }
}
public TimerEventArgs(long clockFreq, long prevTick, long currTick)
{
this.clockFrequency = clockFreq;
this.previousTickCount = prevTick;
this.currentTickCount = currTick;
}
}
/// <summary>
/// 高精度定時器事件委托
/// </summary>
public delegate void HighTimerEventHandler(object sender,TimerEventArgs e);
public class HighAccurateTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
public event HighTimerEventHandler Elapsed;
Thread thread;
private object threadLock = new object();
private long clockFrequency = 0;
private long intevalTicks = 0;
private long nextTriggerTime = 0;
private int intervalMs;
/// <summary>
/// 定時器間隔
/// </summary>
public int Interval
{
get
{
return intervalMs;
}
set
{
intervalMs = value;
}
}
private bool enable;
/// <summary>
/// 啟動定時器標志
/// </summary>
public bool Enabled
{
get
{
return enable;
}
set
{
enable = value;
if (value == true)
{
intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
long currTick = 0;
GetTick(out currTick);
nextTriggerTime = currTick + intevalTicks;
}
}
}
/// <summary>
/// 建構式
/// </summary>
public HighAccurateTimer()
{
if (QueryPerformanceFrequency(out clockFrequency) == false)
{
return;
}
this.intervalMs = 1000;
this.enable = false;
thread = new Thread(new ThreadStart(ThreadProc));
thread.Name = "HighAccuracyTimer";
thread.Priority = ThreadPriority.Highest;
thread.Start();
}
/// <summary>
/// 行程主程式
/// </summary>
private void ThreadProc()
{
long currTime;
GetTick(out currTime);
nextTriggerTime = currTime + intevalTicks;
while (true)
{
while (currTime < nextTriggerTime)
{
GetTick(out currTime); //決定時鐘的精度
}
nextTriggerTime = currTime + intevalTicks;
if (Elapsed != null && enable == true)
{
Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
}
}
}
/// <summary>
/// 獲得當前時鐘計數
/// </summary>
/// <param name="currentTickCount">時鐘計數</param>
/// <returns>獲得是否成功</returns>
public bool GetTick(out long currentTickCount)
{
if (QueryPerformanceCounter(out currentTickCount) == false)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 注銷定時器
/// </summary>
public void Destroy()
{
enable = false;
thread.Abort();
}
}
}
這個方法做的計時器我也用過,不太穩定。
不要在事件里啟動新執行緒,新建thread是要時間的,而是用基于執行緒池的Task,這樣精度可能會高點。
uj5u.com熱心網友回復:
這有一個討論了N多年的問題,回答是“不可能”
https://bbs.csdn.net/topics/330087416
因為windows不是為這種要求設計的系統。跑在windows系統的程式也不需要這種需求(多任務)
如果你一定要如此,只能如上面的帖子盡量選擇一個相對“精確”的方案
如果說非要非要,我們只能建議你使用“DDK”撰寫底層驅動,嘗試直接下時鐘中斷攔截試試
uj5u.com熱心網友回復:
毫秒級?那你不能用.net 運行時不是實時的。有C++吧。如果你要求特別特別精確,推薦你做單片機。
uj5u.com熱心網友回復:
參考 13 樓 wanghui0380 的回復: 這有一個討論了N多年的問題,回答是“不可能”
https://bbs.csdn.net/topics/330087416
因為windows不是為這種要求設計的系統。跑在windows系統的程式也不需要這種需求(多任務)
如果你一定要如此,只能如上面的帖子盡量選擇一個相對“精確”的方案
如果說非要非要,我們只能建議你使用“DDK”撰寫底層驅動,嘗試直接下時鐘中斷攔截試試
timeSetEvent api 如何? 有試過嗎?
uj5u.com熱心網友回復:
參考 5 樓 github_36000833 的回復: 如果實時操作是硬要求(比如輸變電控制),那么你不能用C#,甚至Windows系統也不合適。
因為C#不支持實時操作,Windows系統也不是實時作業系統 。
timeSetEvent api 如何? 有試過嗎?
uj5u.com熱心網友回復:
參考 16 樓 MichaelGLX 的回復: timeSetEvent api 如何? 有試過嗎?
Windows是
搶占式多任務 作業系統。也就是說,作業系統完全域定行程調度方案,作業系統可以剝奪行程的時間片,提供給其它行程。
你的行程,用timeSetEvent也好,用QueryPerformanceCounter也好,不能從根本上排除被作業系統掛起的可能性。
如果在某個15毫秒內,你的行程一點CPU的機會都沒有,又如果去保證1毫秒的操作精度?
uj5u.com熱心網友回復:
1ms只有死回圈并且要當前行程處于很高的優先級。但是也不能保證,因為windows也不是rtos
uj5u.com熱心網友回復:
用圖形桌面系統搞1ms精度的控制?
要控制1ms,你應該放棄任何作業系統底層,自己寫一個作業系統然后燒到設備上。
uj5u.com熱心網友回復:
tickes 毫微秒...........
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/22849.html
標籤:C#
上一篇:請教一下進出庫系統的資料庫設計問題
下一篇:DevExpress提示:無法將型別為"system.drawing.color"的物件強制轉換為型別"system.string"