并行计算中的延迟
本文关键字:延迟 并行计算 | 更新日期: 2023-09-27 18:09:43
我正在使用parallel.for
在许多线程中启动外部程序。但是,尽管这些是单独的线程,但我还是需要像延迟一样实现sth。例如,2 个线程想要同时启动这个外部程序 - 那么其中一个线程应该等待并启动,例如在第二个线程后 10 秒。
可能吗?
这是可能的,但鉴于您提供的信息,这似乎毫无意义......您正在强制执行外部程序的单线程执行,因此您不妨让单个线程执行它。如果Thread 2
必须等待Thread 1
才能启动"外部程序",那么只需Thread 1
完成所有工作,因为它已经知道何时启动"外部程序"。
从多线程方法中获得的唯一好处是,如果您在执行"外部程序"之前需要执行一堆处理,并且该处理必须是并发执行的良好候选者。
更新
好的,有几种方法可以只用一个额外的线程来保持主/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 个多线程版本:
- 使用
Parallel.For
方法:如果外部程序执行时间很短,建议使用 - 我建议在 25 秒以内(尽管这不一定是"正确"的数字(。 - 使用
ThreadPool
:同样,我建议使用少于 25 秒的事情(与上述保留相同(。 - 使用
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;
}
}
如您所见:在这两种情况下,外部处理程序的所有工作都强制到单个线程上,但您的主线程仍然保持响应。
看看生产者-消费者模式。第一个线程生成信息"外部程序启动",第二个线程使用它,等待 10 秒,然后启动外部程序。