• WF4.0 基础篇 (十四) Delay 与WF4中的线程


    本节主要介绍WF的实例是单线程运行的,Delay并不是Thread.Sleep,Parallel是单线程运行的,WorkflowApplication与WorkflowInvoker在调用流程上的区别,InvokeMethod 调用异步方法

    本文例子下载:

    https://files.cnblogs.com/foundation/DelayAndThreadWorkflow.rar

    本文例子说明

    WF的实例是单线程运行的

    在WF3.x与WF4.0中,工作流实例都是单线程执行的

    很多时候,[Parallel]给人一种多线程并行运行的感觉,实际上,Parallel是在单线程中轮换执行各分支。

    这是一篇我在2006年写的关于WF3.x中Parallel的运行说明 http://www.cnblogs.com/foundation/archive/2006/10/10/525630.html

    同时本文也会在后面的讲解中对WF4.0的[Parallel]运行方式加以说明

    Delay 延时

    类名

    System.Activities.Statements.Delay

    文件

    System.Activities.dll

    结构说明

    继承 NativeActivity

    是一个 sealed类

    override 了 [CacheMetadata方法] 与 [Execute方法] 与 [Cancel 方法] 与 [Abort方法]

    override 了[CanInduceIdle 属性]

    [Duration] 属性 的类型为[InArgument<System.TimeSpan>]

    功能说明

    1.延迟,按指定的时间阻止当前的工作流执行。 持续时间过期后,工作流继续执行

    2.[Duration]属性,表示阻止当前的工作流执行的时间

    3.会触发实例的[OnIdel],但在[WorkflowApplicationIdleEventArgs.Bookmarks]中无[Bookmark]

    例:基本使用

    1.在流程中添加一个[WriteLine],打印系统时间

    2.在流程中添加一个[],时间为[10秒]

    3.在流程中再添加一个[WriteLine],打印系统时间

    流程

    宿主

    #region //Delay 例子

    static void workflowCompleted(WorkflowApplicationCompletedEventArgs e)

    {

    System.Console.WriteLine("完成,实例编号:{0},状态:{1}", e.InstanceId, e.CompletionState.ToString());

    }

    static void workflowIdle(WorkflowApplicationIdleEventArgs e)

    {

    System.Console.WriteLine("Idle,实例编号:{0}", e.InstanceId);

    foreach (var item in e.Bookmarks)

    {

    System.Console.WriteLine("BookmarkName:{0}", item.BookmarkName);

    }

    }

    static void delayWorkflow()

    {

    WorkflowApplication instance = new WorkflowApplication(new DelayWorkflow());

    instance.Completed = new Action<WorkflowApplicationCompletedEventArgs>(workflowCompleted);

    instance.Idle = workflowIdle;

    instance.Run();

    }

    #endregion

    结果

    Delay并不是Thread.Sleep ,Parallel是单线程运行的

    1. 当所有分支中的结点都执行完成后,该Parallel结点才结束,继续向下执行
    2. 每分支不是在一个独立的线程上运行的,而是在同一线程中作为一个独立的任务队列运行

    ParallelActivity以下图方式周期性的查看每个分支队列中的第一项,如果是可执行的Activity就执行,如果是不可执行的,(如Delay没到期或挂起没被外部触发)就跳过,执行过程如下

    例:Parallel是单线程运行的

    1.创建一个code Activity,[ThreadSleepActivity],在[Execute]中[Thread.Sleep(10000)]

    2.在工作流中添加一个[Parallel],并添加两个分支

    分支一:添加[ThreadSleepActivity],添加[WriteLine]打印系统时间

    分支一:添加[ThreadSleepActivity],添加[WriteLine]打印系统时间

    ThreadSleepActivity

    public sealed class ThreadSleepActivity : CodeActivity

    {

    protected override void Execute(CodeActivityContext context)

    {

    System.Threading.Thread.Sleep(10000);

    }

    }

    工作流

    宿主

    WorkflowInvoker.Invoke(new ThreadSleepParallelWorkflow());

    结果

    [Parallel]是用单线程完成分支的,所以两个[ThreadSleepActivity],的[Thread.Sleep(10000)]共产生了20秒的延时

    如果[Parallel]是用多线程完成分支的,两个并行的[Thread.Sleep(10000)]会只产生了10秒的延时

    例:Delay并不是Thread.Sleep

    如果将[例:Parallel是单线程运行的]中的[ThreadSleepActivity]换为[Delay]会有什么效果

    1.在工作流中添加一个[Parallel],并添加两个分支

    分支一:添加[Delay]延时10秒,添加[WriteLine]打印系统时间

    分支一:添加[Delay]延时10秒,添加[WriteLine]打印系统时间

    工作流

    宿主

    WorkflowInvoker.Invoke(new DelayParallelWorkflow());

    结果

    结合[例:Parallel是单线程运行的],可以得出Delay并不是Thread.Sleep

    Delay的实现原理我会在后面的文章中详细说明

    WorkflowApplication与WorkflowInvoker在调用流程上的区别

    在WF4.0中,可以使用WorkflowApplication与WorkflowInvoker创建并启动实例.

    但两者在宿主中的线程方式是不一样的

    使用WorkflowInvoker启动工作流时,工作流将附加到宿主的线程中执行

    使用WorkflowApplication启动工作流,工作流实例将在宿主线程之外的另一个线程中运行,使用的是线程池方式

    例:WorkflowInvoker启动工作流

    1.创建一个code activity,[runtimeTestActivity],在[Execute]中循环打印1到10

    2.在工作流程添加[runtimeTestActivity]

    3.在宿主中用WorkflowInvoker方式启动该工作流的两个实例

    runtimeTestActivity

    public sealed class runtimeTestActivity : CodeActivity

    {

    protected override void Execute(CodeActivityContext context)

    {

    for (int i = 1; i <= 10; i++)

    {

    System.Threading.Thread.Sleep(500);

    System.Console.WriteLine(i);

    }

    }

    }

    流程

    宿主

    static void workflowInvoker()

    {

    WorkflowInvoker.Invoke(new runtimeTestWorkflow());

    WorkflowInvoker.Invoke(new runtimeTestWorkflow());

    }

    结果

    可以当第一个实例完成后,第二个实例才启动

    例:WorkflowApplication启动工作流

    1.创建一个code activity,[runtimeTestActivity],在[Execute]中循环打印1到10

    2.在工作流程添加[runtimeTestActivity]

    3.在宿主中用WorkflowApplication方式启动该工作流的两个实例

    runtimeTestActivity

    public sealed class runtimeTestActivity : CodeActivity

    {

    protected override void Execute(CodeActivityContext context)

    {

    for (int i = 1; i <= 10; i++)

    {

    System.Threading.Thread.Sleep(500);

    System.Console.WriteLine(i);

    }

    }

    }

    流程

    宿主

    static void workflowApplication()

    {

    WorkflowApplication instance1 = new WorkflowApplication(new runtimeTestWorkflow());

    WorkflowApplication instance2 = new WorkflowApplication(new runtimeTestWorkflow());

    instance1.Run();

    instance2.Run();

    }

    结果

    第一个实例启动后,第二个实例也启动了,两个实例是同时在两个线程上运行

    InvokeMethod 调用异步方法

    由于WF的实例是单线程运行,在用InvokeMethod调用方法时,就存在二种情况,是在实例的线程内调用方法还是在实例的线程外调用方法.

    [InvokeMethod 调用方法]一节的内容都是在实例的线程内调用方法,现在介绍一下用InvokeMethod 异步调用方法

    当[InvokeMethod]所调用的方法中的线程时,可以将[InvokeMethod]的[RunAsynchronously]属性设为[True]以实现等待调用的方法中的线程完成.

    要使[RunAsynchronously]属性有效,需要用如下方式设计方法

    1.为要实现该功能的方法添加如下两个方法

    IAsyncResult Begin[原史方法] ([原史方法参数], AsyncCallback callback, object asyncState)

    void End[原史方法] (IAsyncResult r)

    2.当[RunAsynchronously]属性设为[False]时, [InvokeMethod]调用[原史方法]

    3.当[RunAsynchronously]属性设为[True]时, [InvokeMethod]调用对应的[Begin原史方法]与[End原史方法]方法

    4.如果没的提供与[原史方法]对应的[Begin原史方法]与[End原史方法]方法, [InvokeMethod]将忽略[RunAsynchronously]属性的值

    MethodName属性的[Begin原史方法]和[End原史方法]不会调用,调用的是[原史方法]

    InvokeMethod 调用异步方法时等待异步方法完成后,流程才继续向下执行

    实现这种调用方式的关键是[IAsyncResult]接口的[CompletedSynchronously 属性]要返回[false]

    1.定义实现[IAsyncResult]接口的[myAsyncResult]

    public class myAsyncResult : IAsyncResult

    {

    public object AsyncState

    {

    get; set;

    }

    public System.Threading.WaitHandle AsyncWaitHandle

    {

    get; set;

    }

    public bool CompletedSynchronously

    {

    get

    {

    return false;

    }

    }

    public bool IsCompleted

    {

    get

    {

    return true;

    }

    }

    }

    2.一个用于[InvokeMethod]调用的[threadMethod]类

    提供一个[myCall],有一个参数n,该方法用于实现计算1到n的累加值,并在屏幕上打印

    [threadMethod]类提供了正常的[myCall]方法,以及为[InvokeMethod]的[RunAsynchronously]使用的[BeginmyCall]与[EndmyCall]方法

    public class threadMethod

    {

    AsyncCallback callback;

    IAsyncResult asyncResult;

    int n;

    int result;

    public void myCall ( int n )

    {

    for (int i = 1; i <= n; i++)

    {

    result = result + i;

    }

    System.Console.WriteLine("myCal, resultl:{0}", result);

    }

    public IAsyncResult BeginmyCall ( int n , AsyncCallback callback, object asyncState)

    {

    System.Console.WriteLine("BeginmyCall,n:{0}", n);

    this.n = n;

    this.callback = callback;

    this.asyncResult = new myAsyncResult() { AsyncState = asyncState };

    System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(myProcessThread));

    thread.Start();

    return this.asyncResult;

    }

    public void EndmyCall (IAsyncResult r)

    {

    Console.WriteLine("EndmyCall, result:{0}",result);

    }

    public void myProcessThread()

    {

    Console.WriteLine("myProcessThread");

    for (int i = 1; i <= n; i++)

    {

    result = result + i;

    System.Console.WriteLine(i);

    System.Threading.Thread.Sleep(500);

    }

    this.callback(this.asyncResult);

    }

    }

    3. 工作流,宿主,结果

    工作流

    宿主

    #region //    InvokeMethod 异步调用方法例子

    static void threadMethodWorkflow()

    {

    WorkflowApplication instance = new WorkflowApplication(new threadMethodWorkflow());

    instance.Completed = completed;

    instance.Run();

    }

    static void completed(WorkflowApplicationCompletedEventArgs e)

    {

    System.Console.WriteLine("流程完º");

    }

    #endregion

    结果

    要注意的是[InvokeMethod]只调用了 BeginmyCall EndmyCall 方法,并没调用 myCall 方法

    InvokeMethod 调用异步方法后不等待异步方法完成后就继续向下执行

    实现这种调用方式的关键是[IAsyncResult]接口的[CompletedSynchronously 属性]要返回[true]

    1.定义实现[IAsyncResult]接口的[myAsyncResult]

    public class myAsyncResult : IAsyncResult

    {

    public object AsyncState

    {

    get; set;

    }

    public System.Threading.WaitHandle AsyncWaitHandle

    {

    get; set;

    }

    public bool CompletedSynchronously

    {

    get

    {

    return true;

    }

    }

    public bool IsCompleted

    {

    get

    {

    return true;

    }

    }

    }

    其他与上例相同

    结果

    要注意的是[InvokeMethod]并没调用 myCall 方法

    [InvokeMethod]调用完 BeginmyCall 方法后就立即调用 EndmyCall 方法,并没有等待 [ myProcessThread() ]的完成

    RunAsynchronously属性设为False时,只执行[原史方法]

    [InvokeMethod.RunAsynchronously]属性设为False时,其他与上例相同

    流程

    结果

  • 相关阅读:
    mysql 压缩备份 压缩还原 命令
    $' ': command not found
    CentOS7查看和关闭防火墙
    Linux系统运维故障排查
    使用netstat、lsof查看端口占用情况
    一道关于二叉树遍历的题目
    curl常用传参方式
    vm centos7中用NAT模式配置上网
    laravel使用过程中一些总结
    MySQL Replication
  • 原文地址:https://www.cnblogs.com/foundation/p/1626617.html
Copyright © 2020-2023  润新知