开发者

Delay in parallel computing

I'm using parallel.for to launch in many threads a external program. But despite the fact that these are separate threads I need implement sth like delay. E.开发者_JS百科g. 2 threads want to launch this external program at the same moment - then one of them should wait and start e.g. 10 sec after second thread.

Is it possible?


It's possible, but given the information you've provided it seems pointless... you're enforcing single-threaded execution of the external program, so you might as well have a single thread executing it. If Thread 2 has to wait for Thread 1 in order to start the "external program," then just let Thread 1 do all the work since it already knows when it started the "external program."

The only benefit you will get from a multi-threaded approach is if you have a bunch of processing that you need to do prior to executing the "external program" and that processing has to be a good candidate for concurrent execution.

Update

OK, there are a couple of ways to do this with only one extra thread in order to keep your Main/GUI thread responsive. The first approach is a simple lock around the external resource which you're interacting with:

public class ExternalResourceHandler
{
    private readonly ExternalResource _resource;
    private readonly object _sync = new object();

    // constructors
    // ...
    // other methods

    public void PerformExternalOperation()
    { 
        lock(_sync)
        {

            Result result = _resource.Execute();

            // do soemthing with the result
        }
    }
}

Here are 3 multi-threaded version for executing the code:

  1. Using a Parallel.For method: recommended if the external program takes a short amount of time to execute- I'd suggest for things under 25 seconds (although this is not necessarily a "correct" number).
  2. Using a ThreadPool: again, I'd recommend for things that take less than 25 seconds (with the same reservation as above).
  3. Using a Thread: this would be recommended if the operation runs longer (i.e. more than 25 seconds, but it would do just as good if it's under 25 seconds).

Here are some examples (not necessarily functional, mostly meant to give you an idea of the different approaches):

public class Program
{
    public static ExternalResourceHandler _erh = new ExternalResourceHandler();

    static int Main()
    {
        Console.WriteLine("Type 'exit' to stop; 'parallel', 'pool' or 'thread' for the corresponding execution version.");
        string input = Console.ReadLine();
        while(input != "exit")
        {
            switch(input)
            {
            case "parallel":
                // Run the Parallel.For version
                ParallelForVersion();
                break;
            caase "pool":
                // Run the threadpool version
                ThreadPoolVersion();
                break;
            case "thread":
                // Run the thread version
                ThreadVersion();
                break;
            default:
                break;
            }
            input = Console.ReadLine();
        }
        return 0;
    }

    public static void ParallelForVersion()
    {
        Parallel.For(0, 1, i =>
        {
            _erh.PerformExternalOperation();
        });
    }

    public static void ThreadPoolVersion()
    {
        ThreadPool.QueueUserWorkItem(o=>
        {
            _erh.PerformExternalOperation();
        });
    }

    public static void ThreadVersion()
    {
        Thread t = new Thread(()=>
        {
            _erh.PerformExternalOperation();
        });
        t.IsBackground = true;
        t.Start();

    }
}

The other option is to employ the Producer/Consumer design pattern where your ExternalResourceHandler is the consumer and it processes requests to the external resource from a thread-safe queue. Your main thread just places requests on the queue and immediately returns back to work. Here is an example:

public class ExternalResourceHandler
{
    private volatile boolean _running;
    private readonly ExternalResource _resource;
    private readonly BlockingQueue<Request> _requestQueue;

    public ExternalResourceHandler( BlockingQueue<Request> requestQueue)
    {
        _requestQueue =  requestQueue;
        _running = false;
    }

    public void QueueRequest(Request request)
    { 
        _requestQueue.Enqueue(request);
    }

    public void Run()
    {
        _running = true;
        while(_running)
        {
            Request request = null;
            if(_requestQueue.TryDequeue(ref request) && request!=null)
            {
                _resource.Execute(request);
            }
        }
    }

    // methods to stop the handler (i.e. set the _running flag to false)
}

Your main would look like this:

public class Program
{
    public static ExternalResourceHandler _erh = new ExternalResourceHandler();

    static int Main()
    {   
        Thread erhThread = new Thread(()=>{_erh.Run();});
        erhThread.IsBackground = true;
        erhThread.Start();

        Console.WriteLine("Type 'exit' to stop or press enter to enqueue another request.");
        string input = Console.ReadLine();
        while(input != "exit")
        {
            _erh.EnqeueRequest(new Request());
            input = Console.ReadLine();
        }

        // Stops the erh by setting the running flag to false
        _erh.Stop();

        // You may also need to interrupt the thread in order to
        // get it out of a blocking state prior to calling Join()
        erhThread.Join();
        return 0;
    }
}

As you see: in both cases all the work for the external handler is forced on a single thread yet your main thread still remains responsive.


Look at producer-consumer pattern. The first thread produces the information "external progam launched" the second thread consumes it, waits 10 second and then launches the external program.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜