8

以下の要件を達成したい。いくつかの解決策を提案してください。

string[] filenames = Directory.GetFiles("C:\Temp"); //10 files

for (int i = 0; i < filenames.count; i++)    
{
    ProcessFile(filenames[i]); //it takes time to execute    
}

マルチスレッドを実装したかったのです。例:10個のファイルがあります。一度に3つのファイルを処理したかった(設定可能、たとえばmaxthreadcount)。したがって、3つのファイルがforループから3つのスレッドで処理され、いずれかのスレッドが実行を完了すると、forループから次の項目を選択する必要があります。また、forループを終了する前に、すべてのファイルが確実に処理されるようにする必要がありました。

最善のアプローチを提案してください。

4

7 に答える 7

22

試す

Parallel.For(0, filenames.Length, i => {
    ProcessFile(filenames[i]);
});

MSDN

.Net4以降でのみ利用可能です。それが受け入れられることを願っています。

于 2012-12-23T14:15:24.367 に答える
5

これにより、.net2.0で機能します。

class Program
{

    static int workingCounter = 0;
    static int workingLimit = 10;
    static int processedCounter = 0;

    static void Main(string[] args)
    {
        string[] files = Directory.GetFiles("C:\\Temp");
        int checkCount = files.Length;
        foreach (string file in files)
        {
            //wait for free limit...
            while (workingCounter >= workingLimit)
            {
                Thread.Sleep(100);
            }
            workingCounter += 1;
            ParameterizedThreadStart pts = new ParameterizedThreadStart(ProcessFile);
            Thread th = new Thread(pts);
            th.Start(file);
        }
        //wait for all threads to complete...
        while (processedCounter< checkCount)
        {
            Thread.Sleep(100);
        }
        Console.WriteLine("Work completed!");
    }

    static void ProcessFile(object file)
    {
        try
        {
            Console.WriteLine(DateTime.Now.ToString() + " recieved: " + file + " thread count is: " + workingCounter.ToString());
            //make some sleep for demo...
            Thread.Sleep(2000);
        }
        catch (Exception ex)
        {
            //handle your exception...
            string exMsg = ex.Message;
        }
        finally
        {
            Interlocked.Decrement(ref workingCounter);
            Interlocked.Increment(ref processedCounter);
        }
    }
}
于 2012-12-23T14:24:20.700 に答える
2

JoeAlbahariによるプロデューサー/コンシューマーキューの例を見てください。それはあなたが達成しようとしていることの良い出発点を提供するはずです。

于 2012-12-23T14:05:45.500 に答える
1

ThreadPoolを使用できます。

例:

ThreadPool.SetMaxThreads(3, 3);

for (int i = 0; i < filenames.count; i++)    
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), filenames[i]);
}

static void ProcessFile(object fileNameObj)
{
    var fileName = (string)fileNameObj;
    // do your processing here.
}

アプリケーションの他の場所でThreadPoolを使用している場合、これはアプリ全体で共有されるため、適切なソリューションではありません。

SmartThreadPoolなどの別のスレッドプール実装を取得することもできます

于 2012-12-23T14:39:36.897 に答える
1

ファイル名ごとにスレッドを開始するのではなく、ファイル名をキューに入れてから、3つのスレッドを開始してそれらを処理します。または、メインスレッドが解放されたので、2つのスレッドを起動して、メインスレッドも動作させます。

Queue<string> MyQueue;

void MyProc()
{
    string[] filenames = Directory.GetFiles(...);
    MyQueue = new Queue(filenames);

    // start two threads
    Thread t1 = new Thread((ThreadStart)ProcessQueue);
    Thread t2 = new Thread((ThreadStart)ProcessQueue);
    t1.Start();
    t2.Start();

    // main thread processes the queue, too!
    ProcessQueue();

    // wait for threads to complete
    t1.Join();
    t2.Join();
}

private object queueLock = new object();

void ProcessQueue()
{
    while (true)
    {
        string s;
        lock (queueLock)
        {
            if (MyQueue.Count == 0)
            {
                // queue is empty
                return;
            }
            s = MyQueue.Dequeue();
        }
        ProcessFile(s);
    }
}

もう1つのオプションは、セマフォを使用して、動作しているスレッドの数を制御することです。

Semaphore MySem = new Semaphore(3, 3);

void MyProc()
{
    string[] filenames = Directory.GetFiles(...);

    foreach (string s in filenames)
    {
        mySem.WaitOne();
        ThreadPool.QueueUserWorkItem(ProcessFile, s);
    }

    // wait for all threads to finish
    int count = 0;
    while (count < 3)
    {
        mySem.WaitOne();
        ++count;
    }
}

void ProcessFile(object state)
{
    string fname = (string)state;
    // do whatever
    mySem.Release();  // release so another thread can start
}

前者は、処理されるファイル名ごとにスレッドを開始および停止するオーバーヘッドがないため、パフォーマンスがいくらか向上します。2つ目は、はるかに短くてクリーンであり、スレッドプールを最大限に活用します。おそらく、パフォーマンスの違いに気付かないでしょう。

于 2013-08-01T19:41:25.800 に答える
0

ParallelOptionsを使用せずに最大スレッドを設定できます

Parallel.Forメソッド(Int32、Int32、ParallelOptions、Action)

ParallelOptions.MaxDegreeOfParallelism

于 2012-12-23T14:34:57.477 に答える
0
var results = filenames.ToArray().AsParallel().Select(filename=>ProcessFile(filename)).ToArray();

bool ProcessFile(object fileNameObj)
{
    var fileName = (string)fileNameObj;

    // do your processing here.

    return true;
}
于 2013-08-01T19:16:35.563 に答える