1

What's the general practice for creating a nested System.Timer? Basically, I need a parent timer that will run indefinitely every 10 seconds, and a child timer that will run a determined length of time every second. The thing I'm having a problem with is how to properly exit the child timer once it's finished.

Here's a simple example - I have a parent timer with a corresponding ElapsedEventHandler. Within this event I make a call to a third party API that returns a list of objects. Now that I have these objects, I need to make extra API calls on each of these objects, one call every second (enter the child timer). Say the first API call brings back 30 objects. I want the ElapsedEventHandler for the child timer to only run 30 times, then exit. I'm just not sure how to implement this.

The reason for my timers is because this third party API imposes a speed limit.

4

3 に答える 3

1

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);
        }
    }
}
于 2013-10-13T07:35:00.743 に答える
0

API 呼び出し元が別のスレッドで実行されている場合は、子タイマーの使用を忘れてください。プルの間にスレッドを 1 秒間スリープさせるだけです。

このようなもの:

foreach(var item in apiObjectsToGet)
{
    api.GetItem(item);
    Thread.Sleep(1000);
}
于 2013-10-10T14:10:06.207 に答える