C# 计时器以秒为单位精确计时
我试图和其他代码并行运行一个无限循环,它在一个特定的时间内以秒为单位执行一次。 在下面的代码中,我试图触摸精确的午夜时间,即:00 hh:00 mm:00秒C# 计时器以秒为单位精确计时,c#,task-parallel-library,infinite-loop,.net-core,timespan,C#,Task Parallel Library,Infinite Loop,.net Core,Timespan,我试图和其他代码并行运行一个无限循环,它在一个特定的时间内以秒为单位执行一次。 在下面的代码中,我试图触摸精确的午夜时间,即:00 hh:00 mm:00秒 using System; // for Date/Time using System.Threading.Tasks; // for Parallel public class Program { public static void Main(string[] args) { Parallel.Invoke( () =>
using System; // for Date/Time
using System.Threading.Tasks; // for Parallel
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
() =>
{
Console.WriteLine("Begin first task...");
}, // close first Action
async () =>
{
Console.WriteLine("Begin second task...");
var midNight = "00:00:00";
while (true)
{
TimeSpan duration = DateTime.Parse(midNight).Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds",
duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.Days >= 1)
await Task.Delay(8640000);
else if(duration.Hours >= 1)
await Task.Delay(360000);
else if(duration.Minutes >= 1)
await Task.Delay(60000);
else
await Task.Delay(1000);
if(duration == TimeSpan.Zero) {
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
} // close second Action `the async task`
) // end of Parallel.Invoke
} // End of Main
} // End of Program
我能够使wait
语句正确工作以达到所需的点,但是锁定条件if(duration==TimeSpan.Zero)
从未变为true
我可以通过改变以下条件来实现:
if(duration == TimeSpan.Zero)
致:
为了避免事件重复发生,我添加了另一个await
级别,因此新的级别如下:
if(duration.Days >= 1)
await Task.Delay(8640000);
else if(duration.Hours >= 1)
await Task.Delay(360000);
else if(duration.Minutes >= 1)
await Task.Delay(60000);
else if(duration.Seconds >= 1)
await Task.Delay(1000);
else
await Task.Delay(500);
我尝试添加如果(duration.millizes>=1)等待(1)
,但没有成功,我的输出如下所示:
问题是,在您的情况下,
持续时间从来都不是零,它从加数毫秒变为减数毫秒
我要做的是:如果持续时间
小于1秒,等待持续时间
,然后假设这是正确的时间。代码:
if (duration.Days >= 1)
await Task.Delay(8640000);
else if (duration.Hours >= 1)
await Task.Delay(360000);
else if (duration.Minutes >= 1)
await Task.Delay(60000);
else if (duration.Seconds >= 1)
await Task.Delay(1000);
else
{
// defensive check in case duration is already negative
// this should not normally happen, but is still possible
if (duration > TimeSpan.Zero)
await Task.Delay(duration);
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
}
这不会给你毫秒精度,但在正常情况下,它应该是正确的秒。首先,你的程序不能像你显示的那样工作,因为你的TimeSpan duration=DateTime.Parse(午夜)。Subtract(DateTime.Now)代码>永远不会是正面的。其次,主函数将几乎立即返回。无论如何,您可以尝试我的解决方案来解决您的问题:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
() =>{Console.WriteLine("Begin first task...");},
async () =>
{
Console.WriteLine("Begin second task...");
DateTime startDate = DateTime.Today;
while (true)
{
TimeSpan duration = DateTime.Now.Subtract(startDate);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds",
duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
int delay = (int)(DateTime.Today.AddDays(1.0).Subtract(DateTime.Now).TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
if(duration.Days >= 1)
{
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
startDate = DateTime.Today;
}
}
}
);
}
}
这将不会为您提供超精度,因为在普通PC上您无法获得它(您可以使用IRQ获得更好的精度,但类似的解决方案要复杂得多)
也作为概念教授
时间版本:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
async () =>
{
Console.WriteLine("Begin second task...");
TimeSpan eventTime = new TimeSpan(0,18,16,53,123); //set when run event (ex. 18:16:53.123)
DateTime endDate = DateTime.Today.Add(eventTime);
if(endDate<DateTime.Now) endDate = endDate.AddDays(1.0);
while (true)
{
TimeSpan duration = endDate.Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds", duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.TotalMilliseconds <= 0.0)
{
Console.WriteLine("It is time... {0}", DateTime.Now);
endDate = endDate.AddDays(1.0);
continue;
}
int delay = (int)(duration.TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
}
}
);
Thread.Sleep(6000);
}
}
使用系统;
使用系统线程;
使用System.Threading.Tasks;
公共课程
{
公共静态void Main(字符串[]args)
{
并行调用(
异步()=>
{
Console.WriteLine(“开始第二个任务…”);
TimeSpan eventTime=新的TimeSpan(0,18,16,53123);//运行事件时设置(例如18:16:53.123)
DateTime endDate=DateTime.Today.Add(eventTime);
如果(enddate)如果我读对了,如果剩下不到一分钟,您仍然会延迟一秒钟(等待任务。延迟(1000);
)?即使只有半秒?这可能是你的问题。如果你使用一个计划的任务来完成这项任务,它会有帮助吗?Quartz.NET是一个库,它可能会帮助你…也可以看到:值得注意的是,除非你能完全确定循环每毫秒会运行几次,否则你试图做的事情可能是不可能的因素(例如垃圾收集)可能会干扰。您最好在到达或经过的时间内设置一个标志。这里有一个不相关但潜在的严重错误:您正在使用async
lambda作为Parllel.Invoke
的参数,它不提供异步支持。第二个参数(Func
)只会一直阻止,直到您点击await
语句。如果您的第一个操作恰好在那时完成,Parallel.Invoke
将完成,程序将立即终止,而无需等待async
委托创建的任务完成。没有确切的时间。这是宇宙量子性质的结果。你到底想做什么?你到底需要走多远?你可能想做等待任务。延迟(TimeSpan.FromDays(1));
,等待任务。延迟(TimeSpan.FromHours(1))
等等,使其更易于阅读。从技术角度来看,您的方法是错误的,因为您的应用程序最终不会说“是时候了”如果在午夜冻结2秒。@Logman,看起来它真的冻结了,但为什么会发生这种情况,仍然没有理解它。@HasanAYousef因为你可能使用普通的计算机而不是RTC系统,所以你不能依赖精确的时间。你的应用程序无法工作可能有多种原因,但检查现在是否是午夜的整个想法是错误的ng.其中一个解决方案是检查你是否过了午夜,然后做点什么并重置计时器。另外,任务。延迟
不保证它会精确等待N毫秒,只保证它至少会等待N毫秒。#Logman能否请你发布一个建议的解决方案,让我测试一下。谢谢你的方法看起来很有逻辑,我会仔细检查星期天,星期一前确认。谢谢如果我想将它与给定的时间进行比较,而不是午夜,该怎么办?@HasanAYousef我有一个小错误(我混合了10s版本和午夜版本)但现在没关系。现在来回答你的问题。你需要计算endDate而不是startDate。然后在持续时间超过0后,你需要重新计算它并完成你的工作。我将在一分钟后发布示例。但为了将来,请将你的需求与你的问题一起发布,不要在以后添加它们,因为它们可能会完全改变实现。@HasanAYousef我添加了新版本。非常感谢,它现在非常完美,我可以达到每毫秒的精度:)请考虑你的备忘录,谢谢。@ Hasayayousf不受欢迎。准确性将严重依赖于你运行Exp的应用程序。如果你在后台进行,用户正在玩电子游戏,在你的应用程序执行你的事件之前可能还要几秒钟。如果你对我的AN满意的话,请再投票。回答。
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
async () =>
{
Console.WriteLine("Begin second task...");
TimeSpan eventTime = new TimeSpan(0,18,16,53,123); //set when run event (ex. 18:16:53.123)
DateTime endDate = DateTime.Today.Add(eventTime);
if(endDate<DateTime.Now) endDate = endDate.AddDays(1.0);
while (true)
{
TimeSpan duration = endDate.Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds", duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.TotalMilliseconds <= 0.0)
{
Console.WriteLine("It is time... {0}", DateTime.Now);
endDate = endDate.AddDays(1.0);
continue;
}
int delay = (int)(duration.TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
}
}
);
Thread.Sleep(6000);
}
}