Улучшение скорости Windows Workflow - PullRequest
2 голосов
/ 24 сентября 2010

У меня есть следующий код, который позволяет мне выполнять рабочий процесс.Это можно было бы назвать неоднократно.И часто есть.Он также живет в веб-сервисе, поэтому к нему может быть одновременно несколько вызовов.Это в настоящее время работает.Но это медленно, так как создание WorkflowRuntime каждый раз очень медленно.

Как я могу улучшить это?

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, я не понимаю, как это будет работать.

... я упускаю что-то простое здесь, есть вероятность, что мой мозгне говорите моему телу, что оно не показывалось на работе сегодня.

Ответы [ 2 ]

0 голосов
/ 10 октября 2010

Я бы сделал пару замечаний по поводу кода, который вы используете в данный момент.Делая все возможное для оптимизации вашего кода, вы должны твердо помнить о цели, когда ваш код достаточно эффективен, так как оптимизация кода имеет тенденцию следовать закону убывающей отдачи, так как оптимизация кода требует все больше и больше усилий.

Самая простая вещь, которую я могу придумать для увеличения скорости кодов, это установить для свойства ValidateOnCreate в экземпляре WorkflowRuntime значение false.По умолчанию установлено значение true, что означает, что каждый раз, когда вы создаете свой экземпляр рабочего процесса.Я предполагаю, что ваш рабочий процесс является статическим в том смысле, что вы не вносите в него динамические изменения во время выполнения, а скорее определяете его во время компиляции.Если это так, вы можете пропустить этап проверки.В зависимости от того, насколько сложен ваш рабочий процесс, это может значительно улучшить скорость кода.

Если предположить, что это не увеличит скорость достаточно, другое предложение следующее.Создайте объекты WaitHandle, Request и Workflow, используемые в экземплярах экземпляра метода Execute класса ApprovalWorkflowRunner.WorkflowRuntime будет параметром для метода Execute.При этом вы должны создавать новый экземпляр класса ApprovalWorkflowRunner каждый раз, когда хотите запустить рабочий процесс ApprovalFlow.Ваш метод 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;
    }

Обратите внимание, что я переключил две строкивнутри обработчика от того, как они были в вашем коде, установка дескриптора ожидания до , когда вы назначаете экземпляр запроса, создает условие состязания.

На последнем замечании: вызов Disposeметод в экземпляре WorkflowRuntime, очевидно, должен был бы иметь место в другом месте вашего кода;однако Microsoft рекомендует вызывать метод StopRuntime до вызова Dispose: Замечания: корректно завершить WorkflowRuntime

Надеюсь, это поможет

0 голосов
/ 06 октября 2010

Одна среда выполнения может запускать несколько рабочих процессов одновременно.Согласно ответу здесь:

На этой странице показан некоторый код для фабрики WorkflowRuntime, который я включу ниже, который, как мне кажется, был первоначально взят из книги Windows Workflow Foundation Пошаговая книга

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;
    }
}
...