在Azure中进行多线程编程的正确方式是什么?

4
我有一个Azure应用程序,需要运行3个独特的长时间运行任务。我可以轻松地启动3个工作角色,但考虑到任务的简单性,这将比我需要花费的成本高3倍。我想在每个线程中运行每个任务,因为每个任务完成所需的时间非常不同,并且运行频率也不同。
在这种情况下,或者是一般的多线程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.
        }
    }
}
4个回答

3
我认为这是一个相当普遍的情况 - 在理想的情况下,每个角色只担任一份工作,但出于经济(和环保)原因,将它们合并成一个角色会更好。我个人认为没有一种“正确”的方法 - 有几种可用的选项,您需要选择最适合您应用程序当前要求的选项:

1

你的问题并不是Azure独有的问题,而是单个CPU上的经典线程问题。(如果你在单个实例中运行多个CPU,最好运行单独的实例,成本相同)。

我非常喜欢TPL,它已经为你解决了许多常见问题,所以我建议使用它。


0
将每个任务制作成单独的 .exe 文件,并从 WorkerRole 类中启动它们。然后监视进程是否意外终止(Process.WaitForExit()),并重新启动它们。(但要考虑如果一个进程不断崩溃会发生什么情况 - 它将使用 100% 的 CPU 启动、崩溃和再次启动。也许可以使用指数退避来管理这个问题。)
我假设您只有一个角色实例来处理这三个任务,在这种情况下,您还必须考虑您的系统如何处理 Azure 由于硬件故障或其他原因而偶尔关闭和重启。(如果有多个实例,它们同时失败的可能性非常小。)

0

我将为每个长期任务启动一个线程。

实际上,在我的其中一个角色中,这就是我所做的:在每个实例中运行多个WorkerRoles

我加载类型并在单独的线程中调用Run方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接