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