10

多くの初期化(強力なマシンでは1〜2秒)が必要なオブジェクトがあります。初期化されると、通常の「ジョブ」を実行するのに約20ミリ秒しかかかりませんが

アプリが使用するたびに再初期化されるのを防ぐために(通常の使用では1秒間に50回、またはまったくない場合があります)、ジョブキューを指定して実行することにしました。独自のスレッドで、キューにそのための作業があるかどうかを確認します。ただし、作業の有無にかかわらず、無期限に実行されるスレッドを作成する方法が完全にはわかりません。

これが私がこれまでに持っているものです、どんな批評も歓迎されます

    private void DoWork()
    {
        while (true)
        {
            if (JobQue.Count > 0)
            {
                // do work on JobQue.Dequeue()
            }
            else
            {
                System.Threading.Thread.Sleep(50);
            }
        }
    }

考えた後:私は、このスレッドを永久に実行させるために、このスレッドを優雅に強制終了する必要があるかもしれないと考えていたので、スレッドを終了するように指示するJobタイプを追加すると思います。このようなスレッドを終了する方法についての考えもありがたいです。

4

6 に答える 6

20

あなたはとにかくする必要があるので、あなたはそうすることができます:lockWaitPulse

while(true) {
    SomeType item;
    lock(queue) {
        while(queue.Count == 0) {
            Monitor.Wait(queue); // releases lock, waits for a Pulse,
                                 // and re-acquires the lock
        }
        item = queue.Dequeue(); // we have the lock, and there's data
    }
    // process item **outside** of the lock
}

次のように追加します:

lock(queue) {
    queue.Enqueue(item);
    // if the queue was empty, the worker may be waiting - wake it up
    if(queue.Count == 1) { Monitor.PulseAll(queue); }
}

キューのサイズを制限するこの質問も確認することをお勧めします(キューがいっぱいになるとブロックされます)。

于 2009-10-14T15:26:23.877 に答える
3

WaitHandle(静的メソッドを見てください)のような同期プリミティブが必要です。このようにして、作業があることをワーカースレッドに「通知」できます。キューをチェックし、キューが空になるまで作業を続けます。空になると、ミューテックスが再びシグナルを送信するのを待ちます。

ジョブ項目の1つも終了コマンドにして、スレッドを終了するときにワーカースレッドに通知できるようにします。

于 2009-10-14T15:26:44.063 に答える
1

ほとんどの場合、私はあなたが設定した方法と非常によく似ていますが、同じ言語ではありません。アイテムがキューに入れられるまでスレッドをブロックし、スリープ呼び出しの必要性をなくすデータ構造(Python)を操作できるという利点がありました。

.NETがそのようなクラスを提供する場合、私はそれを使用することを検討します。スレッドブロッキングは、スリープ呼び出しで回転するスレッドよりもはるかに優れています。

渡すことができるジョブは、「null」のように単純である可能性があります。コードがnullを受け取った場合、しばらくの間から抜け出して家に帰る時間であることがわかります。

于 2009-10-14T15:28:24.870 に答える
1

ParallelFrameworkを入手してください。これには、ジョブキューとして使用できるBlockingCollection<T>があります。使用方法は次のとおりです。

  1. タスク/ジョブを保持するBlockingCollection<T>を作成します。
  2. 無限ループを持ついくつかのスレッドを作成します(while(true){//キューからジョブを取得します)
  3. スレッドを設定します
  4. 利用可能になったときにコレクションにジョブを追加します

アイテムがコレクションに表示されるまで、スレッドはブロックされます。誰の番でもそれを取得します(CPUによって異なります)。私は今これを使っています、そしてそれは素晴らしい働きをします。

また、複数のスレッドが同じリソースにアクセスする、特に厄介なコードの記述をMSに依存するという利点もあります。そして、あなたが誰か他の人にそれを書いてもらうことができるときはいつでも、あなたはそれのために行くべきです。もちろん、彼らがあなたよりも多くの技術/テストリソースと組み合わせた経験を持っていると仮定します。

于 2009-10-14T15:28:50.067 に答える
1

スレッドを終了する必要が本当にない場合(およびアプリケーションの実行を維持しないようにする場合)は、 Thread.IsBackgroundをtrueに設定すると、バックグラウンド以外のすべてのスレッドが終了すると終了します。WillとMarcはどちらも、キューを処理するための優れたソリューションを備えています。

于 2009-10-14T15:30:47.800 に答える
1

私は、whileループを使用したり、パルスしたり、待機したり、実際にThreadオブジェクトにまったく触れたりせずに、バックグラウンドタスクキューを実装しました。そして、それはうまくいくようです。(つまり、過去18か月間、予期しない動作なしに1日に数千のタスクを処理する実稼働環境にあります。)これは、aQueue<Task>とaの2つの重要なプロパティを持つクラスBackgroundWorkerです。ここでは省略して、3つの重要な方法があります。

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
   if (TaskQueue.Count > 0)
   {
      TaskQueue[0].Execute();
   }
}

private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Task t = TaskQueue[0];

    lock (TaskQueue)
    {
        TaskQueue.Remove(t);
    }
    if (TaskQueue.Count > 0 && !BackgroundWorker.IsBusy)
    {
        BackgroundWorker.RunWorkerAsync();
    }
}

public void Enqueue(Task t)
{
   lock (TaskQueue)
   {
      TaskQueue.Add(t);
   }
   if (!BackgroundWorker.IsBusy)
   {
      BackgroundWorker.RunWorkerAsync();
   }
}

待ったり脈打ったりすることがないということではありません。しかし、それはすべて内部で発生しBackgroundWorkerます。これは、タスクがキューにドロップされるたびにウェイクアップし、キューが空になるまで実行されてから、スリープ状態に戻ります。

私は糸脱毛の専門家にはほど遠いです。System.Threading意志を使用する場合、このような問題をいじくり回す理由はありBackgroundWorkerますか?

于 2009-10-15T07:17:01.060 に答える