用c#安排函数在特定时间运行的最简单方法是什么?
本文关键字:运行 最简单 方法 是什么 定时间 函数 | 更新日期: 2023-09-27 18:15:01
如果我在数据库中有很多想要发送的消息,并且每一行都指定了发送消息的日期和时间,以及是否已发送的标志。
这些不会总是在固定的间隔,并且可能需要同时发送多个消息。
在这种情况下,它只是将它们排队并按照它们创建的顺序发送。
让一个函数反复运行是最简单的事情,一旦它完成,它就会再次运行
所以它会:
- 开始运行并查看当前日期/时间
- 检查所有未发送的消息
- 发送在它开始运行之前和之前的所有消息
- 重新开始,取当前日期/时间
我的问题是,持续地让一个方法运行,可能几个小时或几天而不实际发送消息,会不会是非常低效的?
在这种情况下,我认为主要的压力将放在数据库上,它将不断受到查询的冲击。
有更好的方法来安排这样的事情发生吗?
或者只执行上述操作,但每次运行时让它等待5分钟再运行。
工作流4是否提供了适合调度的东西?
您总是可以对序列中的下一个时间值进行先发制人的读取,并在此之前执行单个睡眠,而不是在短睡眠中反复循环。
不确定这是否像您想要的那样详细
也许在数据库中有一个编译视图,该视图返回未发送的消息(我假设每个记录上都有一个标志?),并且预期的发送时间在当前时间之前。然后,Windows服务或控制台应用程序可以在预定的时间间隔内访问该视图(我可以想象,它可以在数据库中进行很好的性能调整),并发送它返回的任何消息。
您可以使用windows服务来完成此操作。或者,如果您正在使用MSSQL,您甚至可以使用SQL Server代理作业。
有几个答案建议先发送一些消息,然后调用sleep,直到下一个消息被发送。
在这种情况下,你的睡眠方式非常重要。
理论上,你可以让一个线程睡几个小时,但是如果在这段时间内应用程序(或服务)需要关闭,那么你就有麻烦了。进程将被终止,不会执行清理。这是一个不太理想的。
不要混淆为工作轮询和在轮询之间睡觉的概念。
如果在下一次轮询数据库之前必须等待5分钟(或5小时),这是可以的,但是您永远不希望*睡眠一次超过一两秒。
我要做的是……
写一个windows服务该服务有一个活动线程,该线程轮询数据库,查看是否有需要发送的消息,并发送它们。然后,它将在可配置的延迟(1分钟,5分钟,1小时,任何合适的)上轮询。
然而,当它等待轮询数据库时,它永远不会休眠超过一秒钟。
如果您可以确保消息只能在DB中的最后一条消息之后添加以发送?如果是这样,您可以检查下一条消息的时间,并且在该时间之前不轮询。
然而,如果我发现下一条消息需要5个小时才需要发送,是否有可能在我等待的时候添加了一条应该在30分钟内发送的消息?
如果是这样,那么你永远不能相信"下一个消息时间",直到那时才进行轮询,你必须不断地在你的固定间隔上进行轮询NB值得再说一遍,你的轮询间隔和你的睡眠间隔不是一回事。
为您编写一个windows服务如何?这个Windows服务将在后台运行,以特定的间隔(例如:每5分钟)检查数据库记录的当前时间,并向人们发送电子邮件,并更新表中相应的记录,将电子邮件发送标志设置为true
你甚至可以有一个SQL作业,它选择没有发送的记录,并与当前时间匹配,并调用一个存储过程调用。net汇编发送电子邮件。dot net组件可以使用SMTPClient发送电子邮件。
这取决于你使用什么。对于您所描述的场景,使用计划任务或服务是完全可以接受的。
如果进程运行得太频繁,您必须小心不要占用资源。如果在高峰时间少运行一次,在非高峰时间多运行一次,效率可能会更高。
无论你喜欢什么方法(创建Windows Service,使用Task Scheduler等),请记住你最初的建议就是所谓的忙碌等待,除非你真的知道你在做什么,否则你应该避免这种情况。
如果你用当没有消息到期时,选择下一个消息到期的时间,然后休眠到那时。
或者使用具有"通知支持"的DB,使整个事情都是事件驱动的,即每当消息到期时,DB会向您发送一个事件。
你可以使用这个。net定时定时器来检查时间间隔,并在特定的时间间隔....运行函数(发送消息)
我会说创建一个带有计时器的windows服务。它可以休眠配置的秒数,然后比较数据库中的日期时间。如果匹配,则发送电子邮件&在数据库中设置已发送电子邮件的标志。
我最近实现了一个windows服务,它利用了C5集合类库中的一个名为IntervalHeap的类。然后我添加了一个持久化层,它可以在服务停止/崩溃的情况下跟踪项目和它们的间隔。
已经投入生产几个月了,并且一直运行良好。
我们在一家金融机构这样做,以便从我们的内部网应用程序发送内部电子邮件。每隔15分钟,调度软件(企业调度程序,而不是Windows计划任务)就会启动一个任务。我们在名为EmailQueue
的表上有一个名为PendingEmail
的视图,该表仅列出了这一轮需要发送的内容(EmailQueue
表有一个PopDate
,这是电子邮件应该发送的有效日期)。应用程序为在PendingEmails
视图中找到的任何内容发送电子邮件。
作业每15分钟发送一次最大批处理大小的电子邮件,标记每条记录是否成功发送或是否有错误(无效的电子邮件地址等),Exception
是什么,以及我们是否想下次重新发送它。它一次更新所有的EmailQueue
表,而不是单独更新每条记录。批量大小的设置是为了防止作业花费超过15分钟的时间,从而导致作业失败。
我不知道每隔一段时间轮询真的会消耗那么多资源,除非你打算每5秒做一次。如果要发送数百万条消息,则可能需要将工作分发到多台机器上。如果您要编写一些自定义代码,我会使用Timer
而不是Thread.Sleep()
,并将Timer
设置为每5分钟或任何您想要执行工作的间隔。
参见Thread.Sleep()
vs. Timer
类:
- 比较使用线程。延迟执行的睡眠和定时器
许多数据库允许由触发器触发事件,例如:"插入后"。触发器由数据库进程/线程运行,它可以采取的操作是特定于数据库的。例如,它可以调用一个C或java过程,该过程向您的电子邮件正在等待或执行的命名信号量发出信号。一个直接的电子邮件应用。查看数据库中的'trigger'或'create trigger'