Задержка в параллельных вычислениях - PullRequest
0 голосов
/ 27 сентября 2011

Я использую parallel.for для запуска во многих потоках внешней программы. Но несмотря на то, что это отдельные потоки, мне нужно реализовать как задержку. Например. 2 потока хотят запустить эту внешнюю программу одновременно - тогда один из них должен подождать и запустить, например. 10 секунд после второй нити.

Возможно ли это?

Ответы [ 2 ]

1 голос
/ 27 сентября 2011

Это возможно, но, учитывая предоставленную вами информацию, она кажется бессмысленной ... вы принудительно выполняете однопоточное выполнение внешней программы, так что вы могли бы иметь один поток, выполняющий ее. Если Thread 2 нужно дождаться Thread 1, чтобы запустить «внешнюю программу», просто позвольте Thread 1 выполнить всю работу, так как он уже знает, когда запустил «внешнюю программу».

Единственное преимущество, которое вы получите от многопоточного подхода, - это если у вас есть куча обработки, которую вы должны выполнить перед выполнением «внешней программы», и эта обработка должна быть хорошим кандидатом для одновременного выполнения.

Обновление

ОК, есть пара способов сделать это только с одним дополнительным потоком, чтобы обеспечить адаптацию потока основного / графического интерфейса. Первый подход - это простая блокировка вокруг внешнего ресурса, с которым вы взаимодействуете:

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 секунд).

Вот несколько примеров (не обязательно функциональных, в основном предназначенных для того, чтобы дать вам представление о различных подходах):

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

Как видите: в обоих случаях вся работа для внешнего обработчика выполняется в одном потоке, но ваш основной поток все еще остается отзывчивым.

0 голосов
/ 27 сентября 2011

Посмотрите на модель производитель-потребитель. Первый поток выдает информацию "запущена внешняя программа", второй поток потребляет ее, ждет 10 секунд и затем запускает внешнюю программу.

...