C# 如何在 For 循环中使用多线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14011411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:23:40  来源:igfitidea点击:

How to use multi threading in a For loop

c#.netmultithreading.net-2.0

提问by SAM

I want to achieve the below requirement; please suggest some solution.

我想达到以下要求;请提出一些解决方案。

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

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

I wanted to implement multi-threading. e.g There are 10 files. I wanted to process 3 files at a time (configurable, say maxthreadcount). So 3 files will be processed in 3 threads from the for loop and if any thread completes the execution, it should pick the next item from the for loop. Also wanted to ensure all the files are processed before it exits the for loop.

我想实现多线程。例如有 10 个文件。我想一次处理 3 个文件(可配置,比如说maxthreadcount)。所以 3 个文件将在 for 循环中的 3 个线程中处理,如果任何线程完成执行,它应该从 for 循环中选择下一个项目。还想确保在退出 for 循环之前处理所有文件。

Please suggest best approach.

请建议最好的方法。

采纳答案by Gregor Primar

This will do the job in .net 2.0:

这将在 .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);
        }
    }
}

回答by RePierre

Take a look at the Producer/Consumer Queue exampleby Joe Albahari. It should provide a good starting point for what you're trying to accomplish.

查看Joe Albahari的生产者/消费者队列示例。它应该为您要完成的工作提供一个良好的起点。

回答by ytoledano

Try

尝试

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

MSDN

MSDN

It's only available since .Net 4. Hope that acceptable.

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

回答by CodingWithSpike

You could use the ThreadPool.

您可以使用ThreadPool

Example:

例子:

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.
}


If you are using the ThreadPool elsewhere in your application then this would not be a good solution since it is shared across your app.

如果您在应用程序的其他地方使用 ThreadPool,那么这不是一个好的解决方案,因为它在您的应用程序中共享。

You could also grab a different thread pool implementation, for example SmartThreadPool

您还可以获取不同的线程池实现,例如SmartThreadPool

回答by David Vu

var results = filenames.ToArray().AsParallel().Select(filename=>ProcessFile(filename)).ToArray();

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

    // do your processing here.

    return true;
}

回答by Jim Mischel

Rather than starting a thread for each file name, put the file names into a queue and then start up three threads to process them. Or, since the main thread is now free, start up two threads and let the main thread work on it, too:

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

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

Another option is to use a semaphore to control how many threads are working:

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

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
}

The first will perform somewhat better because you don't have the overhead of starting and stopping a thread for each file name processed. The second is much shorter and cleaner, though, and takes full advantage of the thread pool. Likely you won't notice the performance difference.

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