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

C# 如何在For循环中使用多线程,c#,.net,multithreading,.net-2.0,C#,.net,Multithreading,.net 2.0,我想达到以下要求;请提出一些解决办法 string[] filenames = Directory.GetFiles("C:\Temp"); //10 files for (int i = 0; i < filenames.count; i++) { ProcessFile(filenames[i]); //it takes time to execute } string[]filenames=Directory.GetFiles(“C:\Temp”)//10

我想达到以下要求;请提出一些解决办法

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

for (int i = 0; i < filenames.count; i++)    
{
    ProcessFile(filenames[i]); //it takes time to execute    
}
string[]filenames=Directory.GetFiles(“C:\Temp”)//10个文件
对于(int i=0;i
我想实现多线程。e、 g有10个文件。我想一次处理3个文件(可配置,比如说
maxthreadcount
)。因此,3个文件将在for循环的3个线程中处理,如果任何线程完成了执行,它将从for循环中选择下一个项目。还希望确保在退出for循环之前处理所有文件

请推荐最佳方法。

请看Joe Albahari的文章。它应该为你想要完成的事情提供一个良好的起点。

试试看

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


它只在.NET4之后才可用。希望可以接受。

这将完成.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);
        }
    }
}
类程序
{
静态int工作计数器=0;
静态int工作极限=10;
静态int processedCounter=0;
静态void Main(字符串[]参数)
{
string[]files=Directory.GetFiles(“C:\\Temp”);
int checkCount=files.Length;
foreach(文件中的字符串文件)
{
//等待自由限制。。。
while(工作计数器>=工作限制)
{
睡眠(100);
}
工作计数器+=1;
ParameterizedThreadStart pts=新的ParameterizedThreadStart(ProcessFile);
螺纹th=新螺纹(pts);
启动(文件);
}
//等待所有线程完成。。。
while(processedCounter
可以设置最大线程数取消并行选项

您可以使用

例如:

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.SetMaxThreads(3,3);
对于(int i=0;i

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


您还可以获取不同的线程池实现,例如,将文件名放入队列,然后启动三个线程来处理它们,而不是为每个文件名启动一个线程。或者,因为主线程现在是空闲的,所以启动两个线程,让主线程也在上面工作:

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);
    }
}
Queue-MyQueue;
void MyProc()
{
string[]filename=Directory.GetFiles(…);
MyQueue=新队列(文件名);
//开始两个线程
线程t1=新线程((ThreadStart)ProcessQueue);
线程t2=新线程((ThreadStart)ProcessQueue);
t1.Start();
t2.Start();
//主线程也处理队列!
ProcessQueue();
//等待线程完成
t1.Join();
t2.连接();
}
private object queueLock=新对象();
void ProcessQueue()
{
while(true)
{
字符串s;
锁(队列锁)
{
如果(MyQueue.Count==0)
{
//队列为空
返回;
}
s=MyQueue.Dequeue();
}
进程文件;
}
}
另一个选项是使用信号量控制有多少线程正在工作:

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
}
Semaphore MySem=新信号量(3,3);
void MyProc()
{
string[]filename=Directory.GetFiles(…);
foreach(文件名中的字符串s)
{
mySem.WaitOne();
QueueUserWorkItem(进程文件,s);
}
//等待所有线程完成
整数计数=0;
而(计数<3)
{
mySem.WaitOne();
++计数;
}
}
无效进程文件(对象状态)
{
字符串fname=(字符串)状态;
//做任何事
mySem.Release();//释放,以便可以启动另一个线程
}

第一种方法的性能稍好一些,因为您不需要为每个处理的文件名启动和停止线程。但是,第二个线程更短、更干净,并且充分利用了线程池。您可能不会注意到性能上的差异。

您真的被困在.NET 2.0上了吗?在.NET3.5或更好的4.0中会有更好的方法。@Joe:有没有使用线程池或信号量的建议?没有,除了:忘了它,除非你的处理是CPU密集型的。光盘的速度并没有神奇地加快。IO将是一个严重的瓶颈内容器。因为除非它做得很多,否则IO将是瓶颈。认真地你知道光盘与CPU内核相比有多慢吗?要平衡这一点需要大量的处理。@TomTom如果文件不需要一段时间读取,可能不会出现瓶颈。也许“执行需要时间”与加载文件后处理文件中的数据有关,在这种情况下,最好使用多线程。如果延迟是因为读取文件需要很长时间,那么我建议忘记多线程处理。举个时间损失的例子,在两个硬盘之间复制一个大文件,看看ETA,然后在上面复制第二个文件,看看ETA是如何增加一倍以上的!你真的只想读1fi
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
}