0

因此,根据MSDN和我读过的许多其他地方,他们使用信号量并在各个线程中阻塞,如下所示:

private static Semaphore _pool;
public static void Main()
{
    _pool = new Semaphore(0, 3);
    for(int i = 1; i <= 1000; i++)
    {
        Thread t = new Thread(new ParameterizedThreadStart(Worker));
        t.Start(i);
    }
}

private static void Worker(object num)
{
    try
    {
        _pool.WaitOne();
        // do a long process here
    }
    finally
    {
        _pool.Release();
    }
}

根据 Main() 中的迭代次数,阻止进程以便您不会一次创建潜在的 1000 个线程不是更有意义吗?例如:

private static Semaphore _pool;
public static void Main()
{
    _pool = new Semaphore(0, 3);
    for(int i = 1; i <= 1000; i++)
    {
        _pool.WaitOne(); // wait for semaphore release here

        Thread t = new Thread(new ParameterizedThreadStart(Worker));
        t.Start(i);
    }
}

private static void Worker(object num)
{
    try
    {
        // do a long process here
    }
    finally
    {
        _pool.Release();
    }
} 

也许两种方式都没有错,这取决于情况?或者一旦有很多迭代,有更好的方法来做到这一点?

编辑:这是一个 Windows 服务,所以我没有阻塞 UI 线程。

4

1 回答 1

2

您通常在线程内执行此操作的原因是您希望使该独占部分尽可能小。您不需要同步整个线程,只需要该线程访问共享资源的地方。

所以更现实的 Worker 版本是

private static void Worker(object num)
{
    //Do a bunch of work that can happen in parallel
    try
    {
        _pool.WaitOne();
        // do a small amount of work that can only happen in 3 threads at once
    }
    finally
    {
        _pool.Release();
    }
    //Do a bunch more work that can happen in parallel
}

(PS 如果您正在做的事情使用 1000 个线程,那么您做错了。您可能更愿意将ThreadPoolTasks用于许多短期工作负载,或者让每个线程做更多的工作。)


这是使用 Parallel.ForEach 的方法

private static BlockingCollection<int> _pool;
public static void Main()
{
    _pool = new BlockingCollection<int>();
    Task.Run(() => //This is run in another thread so it shows data is being taken out and put in at the same time
    {
        for(int i = 1; i <= 1000; i++)
        {
            _pool.Add(i);
        }
        _pool.CompleteAdding(); //Lets the foreach know no new items will be showing up.
    });

    //This will work on the items in _pool, if there is no items in the collection it will block till CompleteAdding() is called.
    Parallel.ForEach(_pool.GetConsumingEnumerable(), new ParallelOptions {MaxDegreeOfParallelism = 3}, Worker);
}

private static void Worker(int num)
{
        // do a long process here
} 
于 2013-07-12T23:28:45.187 回答