【问题标题】:Detecting low user activity and checking email on background检测低用户活动并在后台检查电子邮件
【发布时间】:2012-03-13 15:08:33
【问题描述】:

我正在编写一个必须在后台执行某些操作的应用程序:检查电子邮件并解析它们以将一些数据注入数据库,并连接到 Web 服务以检查某些异步操作的状态。

现在,我的解决方案是一个简单的计时器,它按照预定义的时间表执行这些操作:每五分钟发送一次电子邮件,并且每分钟 Web 服务检查一次(但这些仅在有待处理活动时执行,所以大部分时间这什么都不做。)

目前我没有为此使用线程(我处于开发阶段的早期。)但我的计划是创建一个后台线程并让它离线完成工作。

几个问题:

  1. 我计划控制计时器中的所有内容。设置一个全局变量(基本的“锁定”)启动线程。如果“锁定”已经设置,请忽略它。线程在终止时将其清理干净。我应该为我的线程使用更强大的锁定/队列机制吗? (我已经安装了 OmniThread)
  2. 如何运行低优先级的线程?我不希望应用程序在后台线程执行数据插入或联网时感觉迟缓。
  3. 是否有一种简洁的方法来验证用户活动并仅在用户不忙于键盘/鼠标时启动此线程?

请记住,我对线程没有经验。我曾经写过一个 FTP 同步应用程序,所以我不是一个完整的新手,但那是很久以前的事了。

【问题讨论】:

  • 这是一个允许您创建/编辑发票等的应用程序。但它还需要阅读电子邮件并对其进行解析,以将附加的电子发票作为收到的文件注入,并连接到税务局以获取已提交发票的状态。我不想打扰用户进行这些操作,所以我希望它们在后台运行。
  • 如果您的后台工作与您的应用程序没有直接交互,我建议使用单独的服务(如果您愿意,可以将其设置为低优先级)来运行它们。因此,即使您的应用程序已关闭,甚至没有用户登录,也可以处理这些作品。
  • @Justmade - 我确实希望在新电子邮件(发票)到达时收到一些通知。

标签: multithreading delphi delphi-xe


【解决方案1】:

对于您问题的第 3 部分,Windows API 有一个 GetLastInputInfo 函数,该函数应返回有关用户最后一次执行某项操作的信息。它甚至说它是 “此功能对输入空闲检测很有用”。我确实计划自己使用它,但还没有机会测试它。

编辑:Delphi implementation link

【讨论】:

  • 它工作正常(用于调用屏幕保护程序、任务调度程序空闲任务等)
【解决方案2】:
  1. 我计划控制计时器中的所有内容。设置一个全局变量(基本的“锁定”)启动线程。如果“锁定”已经设置,请忽略它。线程在终止时将其清理干净。我应该为我的线程使用更强大的锁定/队列机制吗? (我已经安装了 OmniThread)

我根本不会打扰计时器。让你的线程的循环看起来像这样,你会有你的延迟。您将不需要锁,因为只有一个线程,它不会休眠,直到上一个作业结束。

procedure YourThread;
var N: Integer;
begin
  while not Terminated do
  begin
    // Figure out if there's a job to do
    // Do the job

    // Sleep for a while, but give the thread a chance to notice
    // it needs to terminate.
    for N := 1 to 500 do
      if not Terminated then
        Sleep(100);
  end;
end;
  1. 如何运行低优先级的线程?我不希望应用程序在后台线程执行数据插入或联网时感觉迟缓。

不要打扰。您可以轻松地使用SetThreadPriority,但这不值得麻烦。如果您的后台线程正在等待 I/O(网络),那么它不会消耗任何 CPU 资源。即使您的后台线程全速运行,您的 GUI 也不会感到迟钝,因为 Windows 在所有可用线程之间分配可用 CPU 时间方面做得很好。

  1. 是否有一种简洁的方法来验证用户活动并仅在用户不忙于键盘/鼠标时启动此线程?

同样,为什么还要检查用户活动?检查电子邮件受网络(即:I/O)限制,检查电子邮件的线程大部分将处于空闲状态。

【讨论】:

  • 在一个线程中睡 50 秒有点过头了。请记住,到了杀死线程的时候,应用程序在最坏的情况下会挂起 50 秒...
  • '请记住,当需要终止线程时,在最坏的情况下,应用程序将挂起 50 秒' - 如果操作系统在应用程序关闭时终止它,则不会。如果线程预计会一直运行到应用关闭,并且您没有明确尝试终止并等待它们,则没有问题 - 应用将立即关闭。
【解决方案3】:

你能不能只在后台线程中做这一切,摆脱所有线程微管理?在我看来,您可以在后台线程中循环调用 sleep(60000) 。每次循环检查网络服务,每 5 次检查电子邮件。如果需要,您可以将优先级设置为 tpLower,但该线程几乎一直处于睡眠或 I/O 阻塞状态,所以我认为它甚至不值得输入。

如果这样的线程在键盘/鼠标上对用户来说是显而易见的,无论它何时运行,我都会感到惊讶。

'设置一个全局变量(基本的“锁定”,)启动线程' - 这个全局变量打算做什么?有什么要锁的?

【讨论】:

  • 我不知道这个帖子需要多长时间才能完成。因此,如果 TTimer 设置为 5 分钟,则较早的调用可能仍处于活动状态;这就是为什么我提到某种形式的锁定。
  • 因为只有一个后台线程,所以大部分时间都在休眠。所以你说这很便宜?
  • @LeonardoHerrera - 应该没问题,是的。使用睡眠循环可以使主线程“脱离它”——不需要计时器。如果一项活动花费的时间超过五分钟,那没关系 - 一项新活动要等到最后一项活动结束后五分钟才能开始。如果这个“抖动”是不可接受的,那么存储上次活动运行开始时的“lastRun”TdateTime 并不难。然后可以在活动之后将新的 sleep() 间隔计算为“trunc((now-lastRun)*msecPerDay)”。注意:如果这个数字是负数,请不要睡觉,否则你会睡很长时间!
  • @LeonardoHerrera - 新邮件通知。在将 TidMessage(或其他)解析到数据库表中之后,您可以 PostMessage() 将 TidMessage 用于主线程,使用 TThread.Synchronize,(呃!),或者您可以使用数据库触发器来触发事件,(似乎有点 OTT)。
猜你喜欢
  • 1970-01-01
  • 2011-05-04
  • 2020-09-21
  • 2016-08-18
  • 2011-06-05
  • 1970-01-01
  • 2017-03-07
  • 2017-12-20
  • 1970-01-01
相关资源
最近更新 更多