0

parallel.for用来在许多线程中启动一个外部程序。但是尽管这些是单独的线程,但我需要实现延迟之类的东西。例如,2 个线程想要同时启动这个外部程序 - 然后其中一个应该等待并在第二个线程之后启动,例如 10 秒。

可能吗?

4

2 回答 2

1

这是可能的,但鉴于您提供的信息似乎毫无意义......您正在强制执行外部程序的单线程执行,因此您不妨让一个线程执行它。如果Thread 2必须等待Thread 1才能启动“外部程序”,那么就让Thread 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 个多线程版本:

  1. 使用Parallel.For方法:如果外部程序需要很短的时间来执行,建议使用 - 我建议在 25 秒内完成(尽管这不一定是“正确”的数字)。
  2. 再次使用ThreadPool: ,我建议花费不到 25 秒的时间(与上面的保留相同)。
  3. 使用 a Thread: 如果操作运行时间较长(即超过 25 秒,但如果它小于 25 秒,它会同样好),建议这样做。

以下是一些示例(不一定是功能性的,主要是为了让您了解不同的方法):

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

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

于 2011-09-27T16:26:01.380 回答
0

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

于 2011-09-27T15:47:13.163 回答