0

我有一个 Windows 窗体应用程序,它从多个设备收集数据 - 并将该数据存储在本地 SQLite 数据库中。然后,在一段时间内,我需要将新记录上传到外部网络服务 - 这意味着我需要读取带有“WasUploaded = 0”字段的新记录,上传它们,然后设置“WasUploaded = 1”成功。今天我会像 10 年前那样做这件事——分叉一个新的后台线程,然后做无限循环:

while(true) 
{
   try
   {
        var newRecords = dbRepo.ReadNew(10);    // read 10 records at a time
        UploadToExternalWebservice(newRecords);
        foreach (var r in newRecords)
        {
            r.WasUploaded = 1;
        }
        dbRepo.CommitChanges(newRecords);
    } 
    catch (Exception ex)
    {
        Logger.LogError(ex);
    }

    Thread.Current.Sleep(15*1000);
}

但我开始怀疑 - 有没有更好的方法可以做到这一点?在这里使用 Tasks 库值得吗?...还有别的吗?

如果这很重要,我在 .Net 4.0 上。

谢谢你。

4

4 回答 4

1

使用计时器。将其设置为每 10 分钟(或其他任何时间),然后进行上传。

System.Threading.Timer uploadTimer = new Timer(UploadProc, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));

void UploadProc(object state)
{
    // do query, upload, and update logic here
}

不需要一个大部分时间都在休眠的显式线程。

如果您希望它更频繁(您的示例中有 15 秒),您可能会遇到可重入计时器滴答声。也就是说,如果您将其设置为 15 秒并且处理时间超过 15 秒,那么您最终将有多个线程同时运行上传代码。

如果这是可能的,您有两个选择:使用锁来防止重新进入,或者使用在每个进程后更新的一次性计时器。

锁很简单。在类范围内定义一个锁对象:

private object uploadLock = new object();

在 UploadProc 内部:

void UploadProc(object state)
{
    if (!Monitor.TryEnter(uploadLock))
    {
        // upload in progress. Quit.
        return;
    }
    try
    {
        // processing here
    } 
    finally
    {
        Monitor.Exit(uploadLock);
    }
}

效果很好。一次性的想法涉及将计时器设置为滴答一次然后停止。然后在完成处理后更新它:

System.Threading.Timer uploadTimer = new Timer(
    UploadProc, null, TimeSpan.FromSeconds(15), TimeSpan.FromMilliseconds(-1));

void UploadProc(object state)
{
    // processing here
    // now reset the timer
    uploadTimer.Change(TimeSpan.FromSeconds(15), TimeSpan.FromMilliseconds(-1));
}
于 2013-03-29T18:59:02.993 回答
0

这是一个基本的推拉问题。如果数据源可以通知您,那么您可以这样做,否则我认为您的方法是正确的。您可以设置不同的服务来提取这些数据。

于 2013-03-29T18:59:48.523 回答
0

使用 Quartz 定期设置工作,使用 Timer 绝对不是最好的方法,你可以,但这是一种快速的肮脏方法。

http://quartznet.sourceforge.net/

你也可以为你的工作使用队列。

于 2013-03-29T19:02:19.483 回答
0

我已经DispatcherTimer为此使用了类。

示例用法:

DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromSeconds(1);
dt.Tick += delegate(object s, EventArgs args) {

//Your Logic here!!    

};
timer.Start();

这里也是类:DispatcherTimer

于 2013-03-29T19:19:50.750 回答