2010-09-23 89 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

希望这有助于