2010-09-23 78 views
2

我有下面的代碼可以讓我執行一個工作流程。這可以被重複調用。往往是。它也生活在一個web服務中,因此可能同時有多個電話。這目前的作品。但它很慢,因爲每次實例化一個WorkflowRuntime都很慢。提高Windows工作流程的速度

我該如何改進?

public class ApprovalWorkflowRunner : IApprovalWorkflowRunner 
{ 
    private static ILogger Logger { get; set; } 
    private static IRepository Repository { get; set; } 

    public ApprovalWorkflowRunner(ILogger logger, IRepository repository) 
    { 
     Logger = logger; 
     Repository = repository; 
    } 

    public Request Execute(Action action) 
    { 
     var request = new Request(); 

     using (var workflowRuntime = new WorkflowRuntime()) 
     { 
      workflowRuntime.StartRuntime(); 
      var waitHandle = new AutoResetEvent(false); 
      workflowRuntime.WorkflowCompleted += ((sender, e) => 
                { 
                 waitHandle.Set(); 
                 request = e.OutputParameters["gRequest"] as Request; 
                }); 
      workflowRuntime.WorkflowTerminated += ((sender, e) => 
                { 
                 waitHandle.Set(); 
                 Logger.LogError(e.Exception, true, action.Serialize()); 
                }); 

      var parameters = new Dictionary<string, object> 
           { 
            {"RepositoryInstance", Repository}, 
            {"RequestID", action.RequestID.ToString()}, 
            {"ActionCode", action.ToString()} 
           }; 

      var instance = workflowRuntime.CreateWorkflow(typeof (ApprovalFlow), parameters); 
      instance.Start(); 
      waitHandle.WaitOne(); 
     } 

     return request; 
    } 
} 

理想情況下,我想保留WorkflowRuntime的一個副本。但是因爲我在CreateWorkflow函數和WorkflowCompleted事件中傳遞了其他對象,所以我沒有看到它是如何工作的。

......我在這裏錯過了一些簡單的東西,這裏有一個很好的機會,我的大腦沒有告訴我的身體,它今天沒有顯示出來工作。

+0

它通常acronymed爲WF。另外請提及你的.NET版本。版本4.0已經有很多改進。 – Aliostad 2010-09-23 21:22:06

+0

@Aliostad,它是3.5,而不是4.0。這是一個在4可用之前開發的應用程序,我們還沒有切換。 – CaffGeek 2010-09-23 21:27:19

回答

0

一個運行時可以同時運行多個工作流程。由於每答案在這裏:

頁面所顯示的WorkflowRuntime的工廠一些代碼,我會在下面包括,我認爲最初是從Windows工作流基礎分步書採取

public static class WorkflowFactory 
{ 
    // Singleton instance of the workflow runtime 
    private static WorkflowRuntime _workflowRuntime = null; 

    // Lock (sync) object 
    private static object _syncRoot = new object(); 

    /// <summary> 
    /// Factory method 
    /// </summary> 
    /// <returns></returns> 
    public static WorkflowRuntime GetWorkflowRuntime() 
    { 
     // Lock execution thread in case of multi-threaded 
     // (concurrent) access. 
     lock (_syncRoot) 
     { 
      // Check for startup condition 
      if (null == _workflowRuntime) 
      { 
       // Provide for shutdown 
       AppDomain.CurrentDomain.ProcessExit += new EventHandler(StopWorkflowRuntime); 
       AppDomain.CurrentDomain.DomainUnload += new EventHandler(StopWorkflowRuntime); 

       // Not started, so create instance 
       _workflowRuntime = new WorkflowRuntime(); 

       // Start the runtime 
       _workflowRuntime.StartRuntime(); 
      } // if 

      // Return singleton instance 
      return _workflowRuntime; 
     } // lock 
    } 

    // Shutdown method 
    static void StopWorkflowRuntime(object sender, EventArgs e) 
    { 
     if (_workflowRuntime != null) 
     { 
      if (_workflowRuntime.IsStarted) 
      { 
       try 
       { 
        // Stop the runtime 
        _workflowRuntime.StopRuntime(); 
       } 
       catch (ObjectDisposedException) 
       { 
        // Already disposed of, so ignore... 
       } // catch 
      } // if 
     } // if 
    } 
} 

只需將致電

WorkflowFactory.GetWorkflowRuntime(); 

編輯: 好的抱歉。您可以嘗試檢查實例是否是您期望的實例,如果不是,則返回。請注意,這段代碼沒有經過測試,只是試圖讓這個想法貫穿始終。

public class ApprovalWorkflowRunner : IApprovalWorkflowRunner 
{ 
    private static ILogger Logger { get; set; } 
    private static IRepository Repository { get; set; } 

    public ApprovalWorkflowRunner(ILogger logger, IRepository repository) 
    { 
     Logger = logger; 
     Repository = repository; 
    } 

    public Request Execute(Action action) 
    { 
     var request = new Request(); 

     var workflowRuntime = WorkflowFactory.GetWorkflowRuntime(); 

     workflowRuntime.StartRuntime(); 
     var waitHandle = new AutoResetEvent(false); 
     WorkflowInstance instance = null; 
     workflowRuntime.WorkflowCompleted += ((sender, e) => 
               { 
                if (e.WorkflowInstance != instance) return; 
                waitHandle.Set(); 
                request = e.OutputParameters["gRequest"] as Request; 
               }); 
     workflowRuntime.WorkflowTerminated += ((sender, e) => 
               { 
                if (e.WorkflowInstance != instance) return; 
                waitHandle.Set(); 
                Logger.LogError(e.Exception, true, action.Serialize()); 
               }); 

     var parameters = new Dictionary<string, object> 
          { 
           {"RepositoryInstance", Repository}, 
           {"RequestID", action.RequestID.ToString()}, 
           {"ActionCode", action.ToString()} 
          }; 

     instance = workflowRuntime.CreateWorkflow(typeof (ApprovalFlow), parameters); 
     instance.Start(); 
     waitHandle.WaitOne(); 

     return request; 
    } 
} 
+0

我遇到的問題是我傳入參數並等待輸出。這仍然可以在WorkflowFactory.GetWorkflowRuntime()中使用嗎?'當多個用戶同時被不同的用戶調用時,它們還能工作嗎?或者事情會變得混雜起來? – CaffGeek 2010-10-06 14:06:51

+0

上面包含編輯 – 2010-10-06 22:29:08

0

我會對您當前使用的代碼進行一些觀察。在做任何事情來優化你的代碼時,你應該牢記當你的代碼足夠高效時的目標,因爲代碼優化趨向於遵循遞減規律,因爲代碼優化需要越來越多的努力。

我想到的可以想到的最簡單的事情就是將WorkflowRuntime實例中的ValidateOnCreate屬性設置爲false。默認情況下,它被設置爲true,這意味着每次創建工作流實例時都是如此。我認爲你的工作流程是靜態的,因爲你沒有在運行時對其進行動態修改,而是在編譯時對其進行了定義。如果是這種情況,您應該可以跳過驗證步驟。取決於您的工作流程有多複雜,這可能會顯着提高代碼的速度。

假定這不會提高速度,其他建議如下。製作在ApprovalWorkflowRunner類的Execute方法實例成員中使用的WaitHandle,Request和Workflow對象。 WorkflowRuntime將是Execute方法的參數。在此過程中,您應該在每次運行ApprovalFlow工作流時創建ApprovalWorkflowRunner類的新實例。然後,您的Execute方法應該是這個樣子:

public Request Execute(Action action, WorkflowRuntime workflowRuntime) { 
      workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted); 
      workflowRuntime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(workflowRuntime_WorkflowTerminated); 

      var parameters = new Dictionary<string, object> 
         { 
          {"RepositoryInstance", Repository}, 
          {"RequestID", action.RequestID.ToString()}, 
          {"ActionCode", action.ToString()} 
         }; 

      mWorkflowInstance = workflowRuntime.CreateWorkflow(typeof(ApprovalFlow), parameters); 
      mWorkflowInstance.Start(); 
      mWaitHandle.WaitOne(); 

     return mRequest; 
    } 

事件處理程序的ApprovalWorkflowRunner類裏面會是這個樣子:

void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e) { 
     if (!e.WorkflowInstance.Equals(mWorkflowInstance)) return; 
     mRequest = e.OutputParameters["gRequest"] as Request; 
     mWaitHandle.Set(); 
     return; 
    } 

注意,我已經從接通處理程序中的兩條線您在代碼中使用它們的方式,在分配請求實例之前在之前設置等待句柄會創建競爭條件。

最後一點:調用WorkflowRuntime實例上的Dispose方法顯然必須在代碼的其他地方進行;然而,微軟建議調用停止運行系統方法之前調用Dispose:Remarks: shut down the WorkflowRuntime gracefully

希望這有助於