1

いくつかの「ワーカー」オブジェクトがオフになり、設定された時間のタスクを実行するプログラムを作成しています。正常に動作する内部タイマーを持つワーカー クラスを作成しました。ただし、「作業」を行っているときは、画面が更新されるまで数秒待つ必要がある場合があります (各ワーカーはリモート画面からデータをスクレイピングし、自動化を行っています)。

これらの一時停止では、スレッドをスリープ状態にしたくありません。これは、他のワーカー オブジェクトのタイマーも一時停止することを理解しているためです (率直に言って、私は C# を初めて使用するため、私のアプリケーションは単一のスレッドです。オーバーリーチしたくなかった)。実際にスレッド全体をハングさせない、使用できる別の待機関数はありますか?

いくつかの追加情報:

  • 現時点ではこれはコンソール アプリですが、最終的には UI フォームを構築して、作業員の作業状況についてユーザーにフィードバックを提供する予定です。
  • 私のタイマーは System.Timers を使用して実装されており、非常にうまく機能しています
  • 私は C# プログラミングの初心者です。これは私の最初のプロジェクトなので、短い言葉でお願いします ;)
  • デスクトップに MS VS Express 2012 を使用する (つまり、C# / .NET のバージョンに関係なく!)

以下のコード (実際の作業は「startWorking」メソッドを使用して行われますが、何も実装されていません。これは、タイマーが動作する私の販売ビルドです。また、メインは現在、複数のタイマーをテストするために使用されています)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Multi_Timers
{
//worker class that includes a timer
public class Worker
{
    private Timer taskTimer;
    private bool available = true;
    private string workerName;
    private string startWork;
    private int workTime;

    // properties
    public bool isAvailable { get { return this.available; } }
    public string name { get { return this.workerName; } }

    // constructor
    public Worker(string name)
    {
        this.workerName = name;
        Console.WriteLine("{0} is initialized", name);
    }

    // start work timer
    public void startWorking(int duration) {

        if (this.available == true)
        {
            this.available = false;
            this.taskTimer = new Timer();
            this.taskTimer.Interval = duration;
            this.taskTimer.Elapsed += new ElapsedEventHandler(doneWorking);
            this.taskTimer.Enabled = true;
            this.startWork = DateTime.Now.ToString();
            this.workTime = duration / 1000;
        }
        else Console.WriteLine("Sorry, {0} was not available to work", this.workerName);
    }

    // Handler for timer
    public void doneWorking(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("{0}: {1} / {2} min / {3}", this.workerName, this.startWork, this.workTime/60, e.SignalTime.ToLocalTime());
        this.taskTimer.Enabled = false;

        this.available = true;

    }
}

//main program
class Program
{
    static void Main(string[] args)
    {
        Random r = new Random();

        // initialize worker(s)
        Worker bob = new Worker("Bob");
        Worker bill = new Worker("Bill");
        Worker jim = new Worker("Jim");

        // q to exit
        while (true)
        {
            if (bob.isAvailable) {

                bob.startWorking(r.Next(1 * 60, 150 * 60) * 1000);
            }
            if (bill.isAvailable)
            {
                bill.startWorking(r.Next(1 * 60, 150 * 60) * 1000);
            }
            if (jim.isAvailable)
            {
                jim.startWorking(r.Next(1 * 60, 150 * 60) * 1000);
            }

        }
    }
}
}

事前に助けてくれてありがとう!このコミュニティの例を読むことは、C# を少し独学で習得する上で非常に重要でした。

4

2 に答える 2

3

私が理解しているように、他のワーカーオブジェクトのタイマーも一時停止するため、スレッドをスリープさせたくありません

それは正しくありません。タイマーは停止しません。

私のアプリケーションはシングルスレッドです

いいえ、そうではありません。タイマーは、他のスレッドを作成および使用して、その動作を実装します。イベント ハンドラーはElapsed、スレッド プール スレッドから起動されます。


コードの主な問題の 1 つは、mainメソッドが 3 つのオブジェクトに対して「busywait」を実行し、それらが完了したかどうかを常にポーリングしていることです。これは...高価です。それは基本的に、「まだそこにいますか」と尋ねる子供のようなものです。1秒間に数百回。あなたが彼らにあなたが終わったと彼らに言うまで彼らがただ待っていたら、それはとてもいいことではないでしょうか! (それはかなり可能であり、可能な選択肢です。)

この場合のより簡単な解決策の 1 つは、 ではなくワーカーでループを実行することMainです。の実装をループでstartWorkingラップし、whilemain を永久に待機させます (つまりThread.Sleep(Timeout.Infinite);)。より複雑なオプションは、ワーカーにTask、イベント、またはブロッキング待機 (「結合」とも呼ばれる) メソッドを提供させて、いつ終了したかを示すことです。

あなたが検討しているオプションThread.Sleepは、少し時間を追加するMainことは役に立ちますが、あなたがいつそこにいるのかをあなたが言うのを待つのではなく、あなたがそこにいる頻度が減ったときにあなたに尋ねるようにあなたの子供に伝えるだけです.そこの。

于 2013-01-23T15:42:06.183 に答える
-1

別のコンテキストで再び実行を遅らせたい場合は、次のような実装を検討できます。

private static void DelayExecution(Action action, TimeSpan delay)
{
    TimeSpan start = DateTime.Now.TimeOfDay;
    Thread t = new Thread(() =>
    {
        while (DateTime.Now.TimeOfDay < start.Add(delay))
        {
            //Block
        }
        action.Invoke();
    });
    t.Start();
}

private static void Main(string[] args)
{
    DelayExecution(() => Console.WriteLine("Delayed Execution"), TimeSpan.FromSeconds(1));
    Console.ReadLine();
}
于 2013-01-23T16:07:15.880 に答える