延迟并行计算

时间:2011-09-27 15:40:13

标签: c# multithreading .net-4.0 parallel-processing parallel-for

我正在使用parallel.for在许多线程中启动外部程序。但是,尽管这些是单独的线程,我需要实现像延迟一样。例如。 2个线程想要在同一时刻启动这个外部程序 - 然后其中一个应该等待并开始,例如第二个帖子后10秒。

有可能吗?

2 个答案:

答案 0 :(得分:1)

这是可能的,但鉴于您提供的信息似乎毫无意义......您正在执行外部程序的单线程执行,因此您可能只有一个线程执行它。如果Thread 2必须等待Thread 1才能启动“外部程序”,那么只需让Thread 1完成所有工作,因为它已经知道它何时启动了“外部程序”。

从多线程方法中获得的唯一好处是,如果在执行“外部程序”之前需要执行大量处理,并且处理必须是并发执行的良好候选者。 / p>

更新

好的,有两种方法可以只使用一个额外的线程来保持主/ GUI线程的响应。第一种方法是围绕您正在与之交互的外部资源进行简单锁定:

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
        }
    }
}

以下是3个用于执行代码的多线程版本:

  1. 使用Parallel.For方法:建议如果外部程序需要很短的时间来执行 - 我建议25秒以内的事情(虽然这不一定是“正确的”数字)。
  2. 再次使用ThreadPool:我建议您花费少于25秒的时间(与上述保留相同)。
  3. 使用Thread:如果操作时间更长(即超过25秒,但如果时间不到25秒,则会更好),建议使用此值。
  4. 以下是一些示例(不一定是功能性的,主要是为了让您了解不同的方法):

    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();
    
        }
    }
    

    另一种选择是采用生产者/消费者设计模式,其中ExternalResourceHandler是消费者,它从线程安全队列处理对外部资源的请求。您的主线程只是将请求放在队列上并立即返回工作。这是一个例子:

    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)
    }
    

    你的主要看起来像这样:

    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;
        }
    }
    

    如您所见:在这两种情况下,外部处理程序的所有工作都强制在一个线程上,但主线程仍然保持响应。

答案 1 :(得分:0)

看看生产者 - 消费者模式。第一个线程产生信息“外部程序启动”第二个线程消耗它,等待10秒然后启动外部程序。