0

I have an app that takes on unknown amount of task. The task are blocking (they wait on network) i'll need multiple threads to keep busy.

Is there an easy way for me to have a giant list of task and worker threads which will pull the task when they are idle? ATM i just start a new thread for each task, which is fine but i'd like some control so if there are 100task i dont have 100threads.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • This is generally called a "Thread Pool" and such an approach is indeed employeed with the TPL (Task Parallel Library). –  Jul 31 '12 at 18:21
  • 1
    Which version of .NET are you using? (.NET 4's Task Parallel Library makes this significantly easier. If you could use async execution in .NET 4.5 it could be even better...) – Jon Skeet Jul 31 '12 at 18:22
  • You could use ThreadPool, it will allocate threads as and when needed – dtsg Jul 31 '12 at 18:22
  • @JonSkeet: I could use either. But i prefer 4 when it comes to async ;) –  Jul 31 '12 at 18:22
  • have you looked at this post? http://stackoverflow.com/questions/444627/c-sharp-thread-pool-limiting-threads – Les Jul 31 '12 at 18:23
  • @Duane I googled that and it looks suspicious or maybe i dont want that. It uses locks(ManualResetEvent) and i dont specify how many threads... http://msdn.microsoft.com/en-us/library/3dasc8as%28v=vs.80%29.aspx –  Jul 31 '12 at 18:24
  • You can specify the number of threads to use via a locking mechanism but i think going for @JonSkeet's TPL suggestion would be better – dtsg Jul 31 '12 at 18:27

2 Answers2

2

Assuming that the network I/O classes that you are dealing with expose Begin/End style async methods, then what you want to do is use the TPL TaskFactory.FromAsync method. As laid out in TPL TaskFactory.FromAsync vs Tasks with blocking methods, the FromAsync method will use async I/O under the covers, rather than keeping a thread busy just waiting for the I/O to complete (which is actually not what you want).

The way that Async I/O works is that you have a pool of threads that can handle the result of I/O when the result is ready, so that if you have 100 outstanding I/Os you don't have 100 threads blocked waiting for those I/Os. When the whole pool is busy handling I/O results, subsequent results get queued up automatically until a thread frees up to handle them. Keeping a huge pool of threads waiting like that is a scalability disaster- threads are hugely expensive objects to keep around idling.

Community
  • 1
  • 1
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • I never used it, is it possible to limit how many task? I need more then the amount of cores on this machine to keep network busy. I cant have 100+ of them because i dont want the network to be too busy –  Jul 31 '12 at 18:31
  • The TPL automatically selects the "right" number- you can force it to specify a number by implementing a scheduler, but I think that you will find that the optimal number is selected for you with no additional work. – Chris Shain Jul 31 '12 at 18:31
  • See http://stackoverflow.com/questions/5235710/tpl-how-can-i-force-tpl-to-use-fixed-of-threads-not-less for more on limiting the number of parallel tasks in TPL – Chris Shain Jul 31 '12 at 18:33
0

here a msdn sample to manage through a threadpool many threads:

using System;

using System.Threading;

public class Fibonacci { public Fibonacci(int n, ManualResetEvent doneEvent) { _n = n; _doneEvent = doneEvent; }

// Wrapper method for use with thread pool.
public void ThreadPoolCallback(Object threadContext)
{
    int threadIndex = (int)threadContext;
    Console.WriteLine("thread {0} started...", threadIndex);
    _fibOfN = Calculate(_n);
    Console.WriteLine("thread {0} result calculated...", threadIndex);
    _doneEvent.Set();
}

// Recursive method that calculates the Nth Fibonacci number.
public int Calculate(int n)
{
    if (n <= 1)
    {
        return n;
    }

    return Calculate(n - 1) + Calculate(n - 2);
}

public int N { get { return _n; } }
private int _n;

public int FibOfN { get { return _fibOfN; } }
private int _fibOfN;

private ManualResetEvent _doneEvent;

}

public class ThreadPoolExample { static void Main() { const int FibonacciCalculations = 10;

    // One event is used for each Fibonacci object
    ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
    Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
    Random r = new Random();

    // Configure and launch threads using ThreadPool:
    Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
    for (int i = 0; i < FibonacciCalculations; i++)
    {
        doneEvents[i] = new ManualResetEvent(false);
        Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
        fibArray[i] = f;
        ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
    }

    // Wait for all threads in pool to calculation...
    WaitHandle.WaitAll(doneEvents);
    Console.WriteLine("All calculations are complete.");

    // Display the results...
    for (int i= 0; i<FibonacciCalculations; i++)
    {
        Fibonacci f = fibArray[i];
        Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
    }
}

}

Hassan Boutougha
  • 3,871
  • 1
  • 17
  • 17
  • I linked that MSDN example in my comments. It looks suspicious with locks(ManualResetEvent) and no example to set thread amount –  Jul 31 '12 at 18:28