4

我是Azure WebJobs的新手,我有一个基本问题。我有一个控制台应用程序部署为WebJob,本质上控制台应用程序使用静态很多,我有一些本地静态变量,如下所示,我会遇到麻烦与多个线程同时更新WebJob这些变量?Azure WebJobs和线程安全

class Program 
{ 
    private static MyService _service; 
    private static int _counter; 

    static void Main() 
    { 
     ... 
    } 

    private static void Method1() { .... } 
} 
+2

这似乎不像它的WebJob相关的所有基本线程安全与静态问题。 – 2014-10-06 16:49:10

+0

“天生的控制台应用程序使用静态很多”---我的不。仅仅因为入口点必须是静态的,并不意味着整个应用程序必须是并发的噩梦。 – 2015-06-03 03:57:15

回答

2

不,除非您在控制台应用程序中专门编写了多线程代码。当WebJob在Azure中调用时,它将获得它自己的进程。例如,以下是来自进程浏览器的一个名为ConsoleTestApp.exe的WebJob的屏幕截图。请注意,它的PID是单独从您的网站在运行W3WP进程。

enter image description here

1

你是什么意思的“线”吗?

你的代码产生的一些实际的线程? (你不会在你的示例代码中显示任何代码)。确实,当你访问静态变量时会遇到麻烦。就像其他任何多线程代码一样。

但我想,你其实并不是指线程,而是分开运行的工作实例。这些是独立的进程,因此每个进程都有自己的静态变量副本。他们甚至不能访问其他内存。

请注意,WebJob只是一个应用程序,与其他任何应用程序一样。没有魔法。如果多次运行相同的应用程序,则每个实例都有自己的内存分配给静态变量。

+0

如果网站被缩小,只有单独的webjob实例。 – Matt 2017-02-15 04:06:44

4

由于您用azure-webjobs-sdk标记了问题,并且我记得前几天有关于SDK的另一个问题,我将假设您的webjob使用SDK,并且多线程是由我们并行运行触发函数。

我回答问题的第一部分是不一定的网络工作相关:

class Program 
{ 
    private static MyService _service; 
    private static int _counter; 

    private static readonly object _lock = new object(); 

    // The 3 blocks of code are thread safe by themselves 
    // but put together, there is no guarantee. Avoid 
    // multiple locks if you can 
    private static void Method1() 
    { 
     // 1. You can use a lock 
     lock(_lock) 
     { 
      // All the code here will be executed by a single thread. 
      // If another thread tries to get the lock, it will have 
      // to wait until the lock is released 

      _service.DoSomething(); 
     } 

     // 2. For atomic operations you can use Interlocked 
     Interlocked.Increment(ref _counter); 

     // 3. For conditional locking 
     if (_service.SomeBooleanProperty) 
     { 
      lock(_lock) 
      { 
       // Check again to see the condition still holds 
       // because it might have changed between the 
       // execution of the first if and the lock 
       if (_service.SomeBooleanProperty) 
       { 
        // Execute the non thread safe code 
       } 
      } 
     } 
    } 
} 

参考了Interlocked

现在我说WebJobs SDK:

如果你想控制并发处理,您可以设置Queue.BatchSize属性。默认情况下为16.如果将其设置为1,则所有内容都按顺序运行。请参阅reference。如果您在使用多实例并发性(同一作业的多个实例)时遇到并发问题,那么Blob租赁是一条可行的路。

+0

感谢Victor,我想确认一下,所以当我使用SDK并将Queue.BatchSize设置为1以外的值时,WebJobs可以启动多个线程来执行我的代码?所以我应该使用lease blob或者将BatchSize设置为1来让WebJobs按顺序运行?如果我不使用SDK,我仍然应该使用lock来保护_service这样的本地变量?你有没有示例代码可以显示如何使用租赁blob?谢谢。 – 2014-10-05 00:55:22

0

我们需要通过类似于ASP.Net请求处理模型的SDK来查看WebJobs的处理。就像在ASP.Net中,在不同线程中处理eash请求一样,在WebJobs SDK中,每个作业的调用都发生在不同的线程中。如果你有静态变量被网络作业操纵,那么就有可能出现问题。如果应用程序中只有一个WebJob,则可以通过将batchsize设置为1来避免这些问题,以便一次只能运行一个作业,并且可以处理静态变量。

但是,如果有多个Web作业函数,并且所有这些使用相同的静态变量,那么批处理大小不会起作用,因为所有类型的至少一个调用将一次运行,并且所有这些操作都是相同的静态变量。

我们对使用静态变量并存在内存泄漏的遗留代码库也有同样的问题。我们正计划派生另一个exe来从webjobs exe中进行实际处理。子exe只接受来自webjob exe的作业所需的参数,并在完成单个作业后自动关闭。所以内存泄漏和遗留代码中的静态变量不会造成任何麻烦。 webjobs exe可以简单地收听子exe中的console.writes,并写入同一个流中,以便在webjobs门户中可见。

1

作业的多个实例将在同一个应用程序域中的不同线程中运行。这意味着静态变量不是线程安全的。

这很容易测试。这也是为什么如果您注册TextWriterTraceListenerSystem.Diagnostics.Trace.Listeners,然后用Trace.WriteLine从多个作业中写入并最终删除它,您将会发生交叉。

本质控制台应用程序使用静态很多

控制台应用程序本质上并不被迫使用静态变量,也不是WebJobs。创建一个类的实例来完成一些处理并调用该类的方法。这里就是一个非常简单的例子:

class Program 
{ 
    public int Start(string[] args) 
    { 
     // You can use non-static variables here 
     Console.WriteLine("There were {0} arguments.", args.Length); 
     return 0; 
    } 

    static int Main(string[] args) 
    { 
     return new Program().Start(args); 
    } 
} 
2

如果你特别希望限制批量大小为一(Azure的WebJob范围内),那么你可以做以下;

static void Main() 
     { 
      InitializeStorage(); 
      JobHostConfiguration config = new JobHostConfiguration(); 
      config.Queues.BatchSize = 1; // the Azure default is 16 
      var host = new JobHost(config); 
      host.RunAndBlock(); 
     } 

阅读本文中的Parallel execution with Queues位了解更多信息。

+0

这就是我正在寻找的东西 - 我们遇到了订购问题,并在此处将'BatchSize'设置为'1',证明它是我们的处理器。现在要弄清楚如何解决它... – moswald 2016-08-12 22:04:40