什么是在Azure中进行多线程处理的正确方法

时间:2011-04-11 22:25:30

标签: multithreading azure parallel-processing

我有一个Azure应用程序需要3个独特的任务才能作为长时间运行的进程运行。我可以很容易地调整3个工作者角色,但考虑到任务的简单性,这将比我需要花费多3倍。我想在自己的线程中运行每个任务,因为每个任务的完成时间和运行需要的频率都非常不同。

鉴于这种情况,甚至是一般的多线程Azure场景,您知道让每项任务独立运行的最佳方式是什么?

我想提出的一些考虑因素是:

  • 保持较低的CPU利用率(使用EventWaitHandles并不总是可以......?)。
  • 使用最新的框架实用程序(即TPL或PLINQ)。
  • 如果出现无法恢复的异常,将正常关闭并重新启动。

感谢您提供建议,链接或代码示例。

修改

以下是我已经解决的问题 - 鉴于代码绑定到Azure云,自我修复选项似乎是最合适的。这种方法旨在采用一系列线程并将其工作委托给各种“工作单元”。

这是如何粘在一起的。首先,一个简单的课程,包括多种工人。

public class ThreadWorker
{
    internal void RunInternal()
    {
        try
        {
            Run();
        }
        catch (SystemException)
        {
            throw;
        }
        catch (Exception)
        {
        }
    }

    public virtual void Run()
    {
    }

    public virtual void OnStop()
    {
    }
}

接下来,使一系列线程无限期保持活动的代码。这涉及一个线程列表,一个“worker”列表(每个线程一个),以及一个无限循环,用于检查给定时间间隔内每个线程的状态。

请注意,终止线程的异常不会拆除其他线程。如果遇到未处理的异常,则下次事件等待句柄响应时将重新启动该线程。

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秒,然后再次检查工作线程的运行状况。

添加worker就像添加从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 个答案:

答案 0 :(得分:3)

我认为这是一个非常常见的情况 - 在一个理想的世界中,每个角色只有一份工作,但出于现金原因(以及环境原因!),最好将它们合并为一个角色。

我个人认为没有正确的方法 - 有多种选择,您需要选择最适合您应用当前要求的选项:

答案 1 :(得分:1)

你的问题不是一个独特的天蓝色问题,它只是单个CPU上的经典线程。 (如果您在单个实例中运行多个CPU,那么您也可以运行单独的实例,这是相同的成本。)

我是TPL的忠实粉丝,它已经为你解决了许多常见问题,所以我认为应该这样做。

答案 2 :(得分:0)

使每个任务成为一个单独的.exe并从您的WorkerRole类中启动它们。从那里监视意外终止的进程(Process.WaitForExit()),并再次启动它们。 (但考虑如果一个进程不断崩溃会发生什么 - 它将使用100%CPU启动,崩溃并再次启动。也许使用指数退避来管理它。)

我假设您只有一个角色实例用于这三个任务,在这种情况下,您还必须考虑系统如何处理由于硬件故障或其他原因而偶尔由Azure关闭和重启。 (对于多个实例,它们不太可能一起失败。)

答案 3 :(得分:0)

我将为这些长寿任务中的每一个开始一个线程。

实际上,这就是我在其中一个角色中所做的:Run multiple WorkerRoles per instance

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