执行任务的最佳方法是每秒不超过一次?

时间:2013-05-31 03:10:32

标签: c# windows windows-runtime

我正在编写一个依赖于JSON API的Windows应用商店应用。 API的提供者要求每秒不超过1个api请求。

所以我创建了一个允许我在阻塞队列上排队请求的类,在后台线程上它会运行一个类似于以下内容的循环:

Loop
{
// this will block until a request is added to the queue
MyRequest = Queue.Take()

// Create task to make the api request here. 

Thread.Sleep(1000)
}

这样,在尝试将另一个请求取消之前,它会等待至少一秒钟。

我发现Thread.Sleep不适用于Windows应用商店。 Task.Delay()似乎不必要地浪费,因为每次调用它都会创建一个新任务。

我觉得可能有一种已知的方法可以做到这一点,我不知道?

谢谢,

2 个答案:

答案 0 :(得分:3)

我知道Task.Delay()似乎很浪费,但微软员工和主持人在MSDN here上推荐

使用.Sleep()或像TGH这样的无限循环会导致程序在等待时变得无响应。如果您希望它在处理队列时有响应,您可以使用以下内容:

await Task.Delay(1000);

答案 1 :(得分:0)

如果您希望任务在后台执行,我建议System.Threading.Timer。将其设置为一次性而非周期性计时器,并在每次请求后刷新它。类似的东西:

System.Threading.Timer myTimer;

// initialize timer
myTimer = new Timer(TimerProc, null, 1000, Timeout.Infinite);

void TimerProc(object state)
{
    // do request here
    // then reset the timer
    myTimer.Change(1000, Timeout.Infinite);
}

这会产生在一个请求结束和下一个请求开始之间等待一秒的效果。

如果您想要以一秒为间隔执行刻度,则必须确保它们不能重叠。这对Monitor来说很容易。您需要一个锁定对象,并使您的计时器成为定期计时器:

object timerLock = new object();

// initialize periodic timer
myTimer = new Timer(TimerProc, null, 1000, 1000);

你的计时器proc:

void TimerProc(object state)
{
    if (!Monitor.TryEnter(timerLock))
    {
        // a request is currently being processed
        return;
    }
    try
    {
        // do request here
    }
    catch (expected exceptions)
    {
    }
    Monitor.Exit(timerLock);
}

请注意,我没有在Monitor.Exit中执行finally。请参阅Eric Lippert的Locks and exceptions do not mix了解原因。