Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 并行计算中的延迟_C#_Multithreading_.net 4.0_Parallel Processing_Parallel For - Fatal编程技术网

C# 并行计算中的延迟

C# 并行计算中的延迟,c#,multithreading,.net-4.0,parallel-processing,parallel-for,C#,Multithreading,.net 4.0,Parallel Processing,Parallel For,我正在使用parallel.for在多个线程中启动一个外部程序。但是,尽管这些线程是分开的,我还是需要实现一些东西,比如延迟。例如,两个线程希望在同一时刻启动此外部程序-然后其中一个线程应等待并在第二个线程后启动,例如10秒 有可能吗?看看生产者-消费者模式。第一个线程生成信息“external program launched”(外部程序已启动),第二个线程使用该信息,等待10秒,然后启动外部程序。这是可能的,但考虑到您提供的信息,它似乎毫无意义。。。您正在强制执行外部程序的单线程执行,因此您

我正在使用
parallel.for
在多个线程中启动一个外部程序。但是,尽管这些线程是分开的,我还是需要实现一些东西,比如延迟。例如,两个线程希望在同一时刻启动此外部程序-然后其中一个线程应等待并在第二个线程后启动,例如10秒


有可能吗?

看看生产者-消费者模式。第一个线程生成信息“external program launched”(外部程序已启动),第二个线程使用该信息,等待10秒,然后启动外部程序。

这是可能的,但考虑到您提供的信息,它似乎毫无意义。。。您正在强制执行外部程序的单线程执行,因此您也可以让单线程执行它。如果
线程2
必须等待
线程1
才能启动“外部程序”,那么就让
线程1
完成所有工作,因为它已经知道何时启动“外部程序”

多线程方法的唯一好处是,在执行“外部程序”之前,您需要进行一系列处理,并且这些处理必须是并发执行的一个很好的候选处理

更新 好的,为了保持Main/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个多线程版本:

  • 使用
    并行。For
    方法:如果外部程序执行时间较短,建议使用此方法-我建议使用25秒以下的时间(尽管这不一定是“正确”的数字)
  • 使用
    ThreadPool
    :同样,我建议使用少于25秒的时间(保留与上面相同的保留)
  • 使用
    线程
    :如果操作运行时间较长(即超过25秒,但如果低于25秒,则效果也一样好),则建议使用
    线程
  • 以下是一些示例(不一定是功能性的,主要是为了让您了解不同的方法):

    另一个选项是采用生产者/消费者设计模式,其中
    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)
    }
    

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

    此外部程序需要很长时间,创建它的线程必须等待结果,因此多线程在这里是必要的(有用的)@Saint,当然,但是,在当前与外部程序交互的线程完成之前,您的另一个线程无法执行任何操作。因此,您只需要两个线程:一个线程处理与外部程序的交互,另一个线程向“处理程序线程”发出请求。处理程序线程一次处理一个请求。
    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;
        }
    }