本節主要介紹WF的實例是單線程運行的,Delay並不是Thread.Sleep,Parallel是單線程運行的,WorkflowApplication與WorkflowInvoker 在調用流程上的區別,InvokeMethod 調用異步方法
本文例子下載:
http://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是單線程運行的
當所有分支中的結點都執行完成後,該Parallel結點才結束,繼續向下執行
每分支不是在一個獨立的線程上運行的,而是在同一線程中作為一個獨立的任務隊列運行
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("流程完o成");
}
#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時,其他與上例相同
相同
流程 結果