什么是定期查询数据库并将数据上传到外部Web服务的正确方法?

时间:2013-03-29 18:55:22

标签: c# .net multithreading

我有一个Windows窗体应用程序,它从多个设备收集数据 - 并将该数据存储在本地SQLite数据库中。然后,在一段时间内,我需要将新记录上传到外部Web服务 - 这意味着我需要使用“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);
}

但我开始怀疑 - 有没有更好的方法可以做到这一点?是否值得在这里使用任务库?还有其他什么?

如果重要的话我在.Net 4.0上。

谢谢。

4 个答案:

答案 0 :(得分: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));
}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

http://quartznet.sourceforge.net/

您还可以使用队列来完成工作。

答案 3 :(得分:0)

我已经使用了DispatcherTimer类。

使用示例:

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

//Your Logic here!!    

};
timer.Start();

这里也是班级:DispatcherTimer