我有一个Azure应用程序,需要运行3个独特的长时间运行任务。我可以轻松地启动3个工作角色,但考虑到任务的简单性,这将比我需要花费的成本高3倍。我想在每个线程中运行每个任务,因为每个任务完成所需的时间非常不同,并且运行频率也不同。
在这种情况下,或者是一般的多线程Azure场景,你知道的最好方法是什么,让每个任务独立运行?
以下是我想提出的几个考虑因素:
- 保持CPU利用率低(使用EventWaitHandles可能并不总是可行)。 - 使用最新的框架实用程序(即TPL或PLINQ)。 - 在无法恢复的异常情况下优雅地关闭和重启。
谢谢您提供建议、链接或代码示例。
编辑
这是我决定采用的方法——考虑到代码绑定了Azure Cloud,自我修复选项似乎是最合适的。这种方法旨在将一组线程和它们的工作委托给各种“工作单元”。
以下是如何将它们粘在一起。首先,一个简单的类来包装不同的工作者。
下面是保持一系列线程永久运行的代码。这涉及到一个线程列表,一个“工作者”列表(每个线程一个),以及一个无限循环,在给定间隔内检查每个线程的状态。
请注意,终止线程的异常不会拆除其他线程。如果遇到未处理的异常,则线程将在下次事件等待句柄响应时重新启动。
最后,我们来谈谈混凝土工人:
在这种情况下,或者是一般的多线程Azure场景,你知道的最好方法是什么,让每个任务独立运行?
以下是我想提出的几个考虑因素:
- 保持CPU利用率低(使用EventWaitHandles可能并不总是可行)。 - 使用最新的框架实用程序(即TPL或PLINQ)。 - 在无法恢复的异常情况下优雅地关闭和重启。
谢谢您提供建议、链接或代码示例。
编辑
这是我决定采用的方法——考虑到代码绑定了Azure Cloud,自我修复选项似乎是最合适的。这种方法旨在将一组线程和它们的工作委托给各种“工作单元”。
以下是如何将它们粘在一起。首先,一个简单的类来包装不同的工作者。
public class ThreadWorker
{
internal void RunInternal()
{
try
{
Run();
}
catch (SystemException)
{
throw;
}
catch (Exception)
{
}
}
public virtual void Run()
{
}
public virtual void OnStop()
{
}
}
下面是保持一系列线程永久运行的代码。这涉及到一个线程列表,一个“工作者”列表(每个线程一个),以及一个无限循环,在给定间隔内检查每个线程的状态。
请注意,终止线程的异常不会拆除其他线程。如果遇到未处理的异常,则线程将在下次事件等待句柄响应时重新启动。
private readonly List<Thread> _threads = new List<Thread>();
private readonly List<ThreadWorker> _workers = new List<ThreadWorker>();
private EventWaitHandle EventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
public override void Run()
{
foreach (var worker in _workers)
{
_threads.Add(new Thread(worker.RunInternal));
}
foreach (var thread in _threads)
{
thread.Start();
}
while (!EventWaitHandle.WaitOne(500))
{
// Restart any threads that have stopped running
for (var i = 0; i < _threads.Count; i++)
{
if (_threads[i].IsAlive)
{
continue;
}
_threads[i] = new Thread(_workers[i].RunInternal);
_threads[i].Start();
}
EventWaitHandle.WaitOne(2000);
}
}
很简单 - 主线程(在本例中为Azure工作角色的Run方法)在检查活动线程列表之间阻塞半秒钟。终止的线程将被重新启动,然后主机线程会阻塞2秒钟,然后再次检查工作线程的状态。
添加工作线程只需添加一组从ThreadWorker基类继承的类列表即可。
_workers.Add(new SomeWorker());
_workers.Add(new AnotherWorker());
最后,我们来谈谈混凝土工人:
public class SomeWorker: ThreadWorker
{
public override void Run()
{
while (true)
{
// Do your long running work here.
Thread.Sleep(2000); // Take a breather - not necessary.
}
}
}
public class AnotherWorker: ThreadWorker
{
public override void Run()
{
while (true)
{
// Do your long running work here.
}
}
}