3

効率的な方法で、定義済みの時間に数十万の関数を実行する必要があります。

私が現在持っているコードは次のようなものです:

class myclass
{
    public DateTime NextTime = DateTime.Now;
    Random rand = new Random();

    public void DoStuff()
    {
        if (NeedToWork())
        {
            // do some complex stuff on a 2nd thread.
            NextTime = DateTime.Now.AddSeconds(rand.Next(60, 3600));
        }
    }

    public bool NeedToWork()
    {
        return DateTime.Now > NextTime;
    }

}

タイマーから実行される呼び出し関数:

    static List<myclass> mylist = new List<myclass>();
    static void Activator()
    {
        foreach (var item in mylist)
        {
            item.DoStuff();
        }

    }

私の問題は、コレクションにアイテムの割り当てがあり、それらすべてを処理するのに非常に長い時間がかかり、場合によっては一部の DoStuff() 関数が 1 分以上遅れて実行されることです。

現在、「Activator」関数は、遅延時間をできるだけ短くするために、異なるスレッドから同時に呼び出されます (必要なスレッド同期は、 を使用して処理されますMutex) 。

私が考えた2つの解決策:

  1. を 1 つ持つ代わりに、1 秒の精度でList<myclass>のような辞書を作成Dictionary<DateTime, List<myclass>>し、1 秒ごとに適切なクラス オブジェクトを実行すると、辞書は「nexttime」を「myclass」インスタンスにマッピングします。
  2. List<>1 つのリストの代わりに 2 つの s またはs を作成しますQueue<>。それらは 'fastqueue' および 'slowqueue' という名前になります。slowqueue にはすべてのオブジェクトが含まれ、fastqueue にはすぐに作業が必要になるすべての項目が含まれ、専用のスレッドが作成されます。スローキューをループし、残り時間を確認してファストキューに入れます。

ノート:

  1. 実際のコードには、次の実行時間を決定するランダム データはありません。実際には何らかの計算に基づいています。これは単なるサンプルです。

  2. 1 つのアイテムの実行には 1 秒もかからず、1 時間に最大 4 回しか実行されません。すべてのコードがここに表示されているわけではありませんが、RAM と CPU のパワーは問題ではありません。

  3. CPU 時間を浪費しているのは、return DateTime.Now > NextTime という行だけです。
4

4 に答える 4

3

どのくらいの計算能力を持っているか分からないので、問題を解決できるとは限りませんが、別のスレッドからParallel.ForEach呼び出す代わりに試してみましたか? Activatorこのようにできます。

Parallel.ForEach(mylist, item =>
{
    item.DoStuff();
});

同時に動作するスレッドの数を制限したい場合は、 MaxDegreeOfParallelismwhen callingを設定することもできます。Parallel.ForEach私の答えが明確でない、または詳細でない場合は、コメントを残してください。

編集:コメントが正当に述べてDoStuff()いるように、私の例では同期的に実行されます。Task.Factory.StartNew()または同等のものを使用して、タスクスケジューラを利用すると役立つ場合があります。ただし、著者は、ほとんどのタスクは非常に小さく、非常に短時間で実行されると述べています。そのため、実際のスケジューリングでは、異なるスレッドでのシリアル実行ではなく、不要なオーバーヘッドが発生すると思います。

于 2012-12-31T19:02:57.280 に答える
3

実行時間でソートされた、ソートされたキューまたは作業ツリーを維持したい場合があります。

次に、通常のインターバル タイマー ループがキューから最初の N 個のアイテムを実行し、アイテムが現在のインターバル時間を超えると停止します。これ以上調べる必要がないためです。

並べ替えられたデータ構造を使用してキューに追加する新しい作業を生成する場合、挿入は並べ替えを維持するために適切に配置する必要があります。

(キューに追加したりキューから削除したりする際には、スレッド セーフについても考慮する必要があります。)

(参考までに、スケジューリングアルゴリズムには多くのバリエーションがあります。)


別の注意として、それが役に立つかどうかはわかりませんが、これらの種類の時間ベースの数式を使用する場合は、DateTime.Now のスナップショットを作成して数回使用することを検討してください。 DateTime.Now の呼び出し間で中断される

public void DoStuff(DateTime now)
{
    if (NeedToWork(now))
    {
        // do some complex stuff on a 2nd thread.
        NextTime = now.AddSeconds(rand.Next(60, 3600));
    }
}
于 2013-01-08T22:29:51.740 に答える
1

デルタキュー - タイムアウト時間でソートされたリストは、多数の長いタイムアウトを処理する一般的な方法です。1 つのスレッドを使用してリストを管理します。これは、現在とリストの先頭にあるアイテムのタイムアウト時間の間の間隔に設定されたタイムアウトで、入力 BlockingCollection キューを待機します。待機がタイムアウトした場合、キューの先頭にあるアイテムをポップして起動し、新しいヘッド オブジェクトを取得し、その待機時間を再計算して、入力キューで再び待機します (リストが空の場合、タイムアウトは INFINITE に設定されます)。新しいタイムアウト項目は入力キューにプッシュされ、スレッドはタイムアウト アクティビティを再開する前にそれらを挿入します。

于 2013-01-09T09:14:00.730 に答える
0

実行しようとしているタスクの複雑さと、所有しているハードウェア リソースの量によって異なりますが、この種のジョブにはライブラリを使用することをお勧めします。Quartz.netが役立つ場合があります。

于 2012-12-31T19:03:39.683 に答える