创建嵌套System.Timer
的一般做法是什么? 基本上,我需要一个每 10 秒无限期运行的父计时器,以及一个每秒运行确定时间长度的子计时器。 我遇到的问题是如何在完成后正确退出子计时器。
这是一个简单的例子 - 我有一个带有相应ElapsedEventHandler
的父计时器. 在此事件中,我调用返回对象列表的第三方 API。 现在我有了这些对象,我需要对每个对象进行额外的 API 调用,每秒调用一次(输入子计时器(。 假设第一次 API 调用返回 30 个对象。 我希望子计时器的ElapsedEventHandler
只运行 30 次,然后退出。 我只是不确定如何实现这一点。
我的计时器的原因是因为这个第三方 API 施加了速度限制。
您是否需要每 10 秒获取一次,或者在处理完所有数据后获取一次? 您提到每 10 秒获取一次数据,但返回 30 个项目。 按照这个速度,你将继续分配内存,因为它永远无法赶上。
1 秒计时器,然后递增一个静态计数器,每 10 次迭代一次获取数据。检索数据后,每个项目每秒都会从堆栈中弹出。
using System;
using System.Collections.Generic;
using System.Threading;
namespace TimedFetch
{
class Program
{
static System.Threading.Timer workTimer;
static Stack<string> itemList;
public static AutoResetEvent fetchDataEvent;
static int eventCounter;
public class ExternalDatamanager
{
public void FetchData()
{
DateTime startTime = DateTime.Now;
do
{
FetchHeaderData();
fetchDataEvent.WaitOne();
Console.WriteLine("{0} FetchData Signaled! List size {1}", DateTime.Now.ToLongTimeString(), itemList.Count);
} while(true);
}
private static void FetchHeaderData()
{
// replace this with your method of retrieving data
Console.WriteLine("{0} FetchHeaderData", DateTime.Now.ToLongTimeString());
DateTime timeObject = DateTime.Now;
for (int i = 0; i < 30; i++)
{
lock (itemList)
{
itemList.Push(timeObject.ToLongTimeString());
timeObject = timeObject.AddSeconds(1);
}
}
}
}
static void Main(string[] args)
{
eventCounter = 0;
itemList = new Stack<string>();
fetchDataEvent = new AutoResetEvent(false);
ExternalDatamanager dataManager = new ExternalDatamanager();
Thread workerThread = new Thread(new ThreadStart(dataManager.FetchData));
workerThread.Start();
workTimer = new System.Threading.Timer(workTimer_Elapsed, null, 0, 1000);
}
// executes once a second
private static void workTimer_Elapsed(Object state)
{
Console.WriteLine("{0} Fire!", DateTime.Now.ToLongTimeString());
Interlocked.Increment(ref eventCounter);
lock (itemList)
{
// every 10 seconds
if (itemList.Count > 0)
FetchDetail(itemList.Pop());
// else ??
// { ??
if (eventCounter % 10 == 0)
fetchDataEvent.Set();
// } ??
}
}
private static void FetchDetail(string headerRecord)
{
Console.WriteLine("{0} Fetch detail for {1}", DateTime.Now.ToLongTimeString(), headerRecord);
}
}
}
听起来您只需要一个全局处理队列,其中包含一个计时器,该计时器设置为API供应商强加给您的任何限制间隔。所有 API 请求都将排队,任何需要更多子请求的 API 请求的结果也会排队。您有一个计时器,每秒处理队列上的下一个项目。
这是我正在谈论的示例。我会为每个 API 请求创建一个子类,以便它将 a( 正确处理请求和 b( 根据需要对子任务进行排队,如果需要,根据当前 API 请求的结果设置子任务的状态:
void Main()
{
Timer t = new Timer(ProcessNextItem, null, 0, 1000);
}
public void ProcessNextItem(object o){
var nextTask = Tasks.Take();
nextTask.Process(); // Process does the API calls and enqueues new tasks onto Tasks, and sets state of child tasks as needed
}
public static BlockingCollection<APIRequestTask> Tasks = new BlockingCollection<APIRequestTask>(new ConcurrentQueue<APIRequestTask>());
public abstract class APIRequestTask{
public void Process(){}
public object State {get;set;}
}
如果 API 调用方在单独的线程上运行,请忘记使用子计时器。 只需在拉动之间让线程休眠一秒钟即可。
像这样:
foreach(var item in apiObjectsToGet)
{
api.GetItem(item);
Thread.Sleep(1000);
}