4

我是 Azure WebJobs 的新手,我有一个基本问题。我有一个控制台应用程序部署为 WebJob,本质上控制台应用程序经常使用静态,并且我有一些局部静态变量,如下所示,如果多个线程同时通过 WebJob 更新这些变量,我会遇到麻烦吗?

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

    static void Main()
    {
      ...
    }

    private static void Method1() { .... }
}
4

6 回答 6

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,则一切都按顺序运行。请参阅此处的参考。如果您在多实例并发(同一作业的多个实例)方面遇到并发问题,那么 Blob 租约是可行的方法。

于 2014-10-04T17:11:17.303 回答
2

不,除非您在控制台应用程序中专门编写多线程代码,否则不会。在 Azure 中调用 WebJob 时,它将获得自己的进程。例如,下面是来自名为 ConsoleTestApp.exe 的 WebJob 的进程资源管理器的屏幕截图。请注意,它的 PID 与您的网站运行的 W3WP 进程是分开的。

在此处输入图像描述

于 2014-10-04T15:57:54.227 回答
2

如果您特别想将批处理大小限制为 1(在 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();
        }

阅读本文中的使用队列并行执行位以获取更多信息。

于 2015-11-10T12:48:47.563 回答
1

“线程”是什么意思?

您的代码产生的一些实际线程?(您的示例代码中没有显示任何内容。)事实上,当您访问静态变量时会遇到麻烦。就像任何其他多线程代码一样。

但我认为,您实际上并不是指线程,而是指工作的单独运行实例。这些是独立的进程,因此每个进程都有自己的静态变量副本。他们甚至无法访问彼此的内存。

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

于 2014-10-04T16:02:04.510 回答
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);
    }
}
于 2015-10-28T17:26:40.573 回答
0

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

但是,如果有多个 Web 作业函数并且所有这些函数都使用相同的静态变量,那么批量大小将无济于事,因为来自所有类型的至少一个调用将同时运行,并且所有这些函数都操作相同的静态变量。

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

于 2015-07-20T15:18:22.857 回答