0

I'm writing a little Proxy checker. I use this to manage the threads

que = new Queue<Proxy>(_settings.Proxies);

while (que.Count > 0)
{
    lock (que)
    {
        while (running >= _settings.Threads) {}

        Proxy cProxy = que.Dequeue();
        CheckProxyAsync(cProxy);
        Console.WriteLine(running);
    }
}

I thought it would be a good idea to use async methods with callbacks to manage it!

this is the "CheckProxyAsync" function:

private void CheckProxyAsync(Proxy p)
{
    InvokeDelegate.BeginInvoke(p, Callback, null);
}

this is my callback:

private void Callback(IAsyncResult ar)
{
    var returnTuple = InvokeDelegate.EndInvoke(ar);
    if (!returnTuple.Item1) //if failed
    {
        if (!_settings.Retry || returnTuple.Item2.Retries > _settings.RetryCount) //if no retry or retry count is reached
            _settings.Proxies.Remove(returnTuple.Item2); //Dead proxy :(
        else que.Enqueue(returnTuple.Item2); //try again
    }
    else //if success
    {
        Interlocked.Increment(ref filteredProxies);
        Interlocked.Decrement(ref leftProxies);

        if (returnTuple.Item2.ProxyAnonymity == Anonymity.L1)
            Interlocked.Increment(ref l1Proxies);
        else if (returnTuple.Item2.ProxyAnonymity == Anonymity.L2)
            Interlocked.Increment(ref l2Proxies);
        else if (returnTuple.Item2.ProxyAnonymity == Anonymity.L3)
            Interlocked.Increment(ref l3Proxies);

    }
    OnUpdate();

}

As you can see in the manager function I print out the running thread count to the console. The count is getting updated at the start and at the end of the function "CheckProxy" to which the delegate "InvokeDelegate" belongs. but the maximum parallel running async methods are 8, but I want more! How can I increase the limit?

coolerfarmer
  • 385
  • 2
  • 9
  • 2
    You should be aware that your delay loop, `while (running >= _settings.Threads) {}` could fail to terminate. The compiler could generate code that assumes that the values don't change. Also, that is a busy wait loop that essentially pegs one CPU. You might consider a less expensive way of delaying. A `Semaphore` would be a good way to do this. – Jim Mischel Jun 20 '14 at 19:35
  • @JimMischel A `BlockingCollection` would be better still, as it'll manage all of the synchronization on your behalf. – Servy Jun 20 '14 at 19:47
  • @Servy: Maybe. It would be difficult for `BlockingCollection` to limit the number of concurrent threads. – Jim Mischel Jun 20 '14 at 20:36
  • @JimMischel It wouldn't need to. You create and fill the BC, start X units of work, and have each of them get their next unit of work from the BC when they finish. This results in X consumers. The BC doesn't *create* those consumers, you do, but all of those consumers can be given a single BC to manage the pipeline of data to all of those workers. – Servy Jun 20 '14 at 20:39
  • @Servy: I see your point. Restructure the program so that X threads pull items from the queue as needed, rather than having a main thread orchestrating it. – Jim Mischel Jun 20 '14 at 20:42

1 Answers1

1

Leave this up to the thread pool. It almost certainly knows better than you what the optimal number of threads are.

Fundamentally your CPU is only capable of performing so many operations at one time. Creating more than a certain number of threads adds a lot of overhead in which cores are constantly swapping out which thread should be currently executing, while adding no additional throughput. Once you get to that point adding threads would increase each actions responsiveness, and improve the speed at which it gets started, but at the cost of total throughput.

If you really want to have more threads than that, you'll need to not use the thread pool and instead create thread explicitly. But if you're going to do this, you should really be sure that you know what you're doing, and know why the thread pool's allocation algorithm isn't well suited for you.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    But in this case I have to wait most of the time for the proxies to answer! So it's not CPU intensive at all! So there's no way to do this with delegates/managed tasks? So I have to switch over to Threads? – coolerfarmer Jun 20 '14 at 19:41
  • @user3676570 If it's not CPU bound work *then you don't need a bunch of threads to manage the work*. You only need multiple threads to manage CPU bound work. When you have IO bound work, unless you do something silly like create a thread who's sole purpose is to sit there and do a blocking wait on that IO, there is no thread that needs to be doing anything to handle the asynchronous IO. – Servy Jun 20 '14 at 19:44
  • 1
    @user3676570 You need to realize that [you can do work in parallel using asynchrony without creating additional threads](http://stackoverflow.com/a/23833635/1159478). – Servy Jun 20 '14 at 19:46
  • You are awesome! I really like the way you explain things! I hope I understood it now a bit better! but I have no idea how I can implement it in my proxy checker! I know that I don't really need multi threading, since it's not cpu intensive. Can you point me a good resource to learn about TPL? – coolerfarmer Jun 20 '14 at 19:55
  • Oh, if I get it right it's the `async` and `await` operators that came with .Net 4.5? Am I right? – coolerfarmer Jun 20 '14 at 19:56
  • @user3676570 Inherently whatever you'd doing to provide IO needs to provide some form of asynchrony. It could be a method that returns a `Task`, it could be a method that accepts a callback, it could be a method that returns an `IAsyncResult`, fires an event when it completes, or something else entirely (some also provide multiple options). You can turn any of them into a `Task` if you want, or you can work with them using those given paradigms. `await` is specific to C# 5.0, not to .NET 4.5, C# and .NET are separate concepts. – Servy Jun 20 '14 at 20:00
  • Ok, I'm going to try this out real quick. But I have another question. `async` and `await` aren't using multiply threads, but how do they do the work then? Is it like this: `async void Function1 -> Something like { Task asyncTask = GetSomeResult(); DoSomeOtherSutff(); Result r = await asyncTask; } Let's say GetSomeResult maked a webrequest and waits for the result. It only uses one thread, right? And it works like this: Function1 gets called -> Create WebRequest and waits for data. While waiting for the response it executes "DoSomeOtherStuff" Is it right? – coolerfarmer Jun 20 '14 at 20:10
  • Just read up on the concept, read some tutorials, a book, etc. It's not something conducive to me explaining in comments. – Servy Jun 20 '14 at 20:20
  • Whoever downvoted this, you should at least give a reason why. This is a good, and very correct, answer to the question posed. – Jim Mischel Jun 20 '14 at 20:39