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

它仅从.Net 4 开始可用。希望可以接受。

于 2012-12-23T14:15:24.367 回答
5

这将在 .net 2.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

看看 Joe Albahari 的Producer/Consumer Queue 示例。它应该为您要完成的工作提供一个良好的起点。

于 2012-12-23T14:05:45.500 回答
1

与其为每个文件名启动一个线程,不如将文件名放入一个队列,然后启动三个线程来处理它们。或者,由于主线程现在空闲,启动两个线程并让主线程也处理它:

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);
    }
}

另一种选择是使用信号量来控制有多少线程正在工作:

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
}

第一个会执行得更好,因为您没有为每个处理的文件名启动和停止线程的开销。然而,第二个更短更干净,并且充分利用了线程池。您可能不会注意到性能差异。

于 2013-08-01T19:41:25.800 回答
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 回答
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 回答
0

可以设置最大线程数取消 ParallelOptions

Parallel.For 方法(Int32、Int32、ParallelOptions、Action)

ParallelOptions.MaxDegreeOfParallelism

于 2012-12-23T14:34:57.477 回答