分享
 
 
 

任务并行

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: |||超大  

本文内容并行编程任务并行隐式创建和运行任务显式创建和运行任务任务 ID任务创建选项创建任务延续创建分离的子任务创建子任务等待任务完成组合任务任务中的异常处理取消任务TaskFactory 类无委托的任务相关数据结构参考资料下载 Demo下载 Samples for ParallelPRogramming with .net framework并行编程多核 CPU 已经相当普遍,使得多个线程能够同时执行。将代码并行化,工作也就分摊到多个 CPU 上。

过去,并行化需要线程和锁的低级操作。而 Visual Studio 2010 和 .NET Framework 4 开始提供了新的运行时、新的类库类型以及新的诊断工具,从而增强了对并行编程的支持。这些功能简化了并行开发,通过固有方法编写高效、细化且可伸缩的并行代码,而不必直接处理线程或线程池。

下图从较高层面上概述了 .NET Framework 4 中的并行编程体系结构。

任务并行库(The Task Parallel Library,TPL)是System.Threading和System.Threading.Tasks空间中的一组公共类型和 API。TPL 的目的是通过简化将并行和并发添加到应用程序的过程来提高开发人员的工作效率。TPL 能动态地最有效地使用所有可用的处理器。此外,TPL 还处理工作分区、ThreadPool 上的线程调度、取消支持、状态管理以及其他低级别的细节操作。通过使用 TPL,你可以将精力集中于程序要完成的工作,同时最大程度地提高代码的性能。

从 .NET Framework 4 开始,TPL 是编写多线程代码和并行代码的首选方法。但并不是所有代码都适合并行化,例如,如果某个循环在每次迭代时只执行少量工作,或它在很多次迭代时都不运行,那么并行化的开销可能导致代码运行更慢。 此外,像任何多线程代码一样,并行化会增加程序执行的复杂性。 尽管 TPL 简化了多线程方案,但建议对线程处理概念(例如,锁、死锁和争用条件)进行基本了解,以便能够有效地使用 TPL。

任务并行“任务并行”是指一个或多个独立的任务同时运行。好处当然是系统资源的使用效率更高,可伸缩性更好;对于线程或工作项,可以使用更多的编程控件。因此,在 .NET Framework 中,TPL 是用于编写多线程、异步和并行代码的首选 API。

隐式创建和运行任务Parallel.Invoke方法提供了一种简便方式,可同时运行任意数量的任意语句。只需为每个工作项传入 Action 委托即可。

下面的示例演示Invoke调用,创建并启动同时运行三个任务。将对共享数据达尔文的《物种起源》执行三项操作:最长的词、最频繁出现的词和字数。这些操作都不修改源,因此它们可以直接并行执行。

usingSystem;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Threading.Tasks;

 

namespaceParallelInvokeDemo

{

classProgram

{

staticvoidMain(string[] args)

{

// Retrieve Darwin's "Origin of the Species" from Gutenberg.org.

string[]Words = CreateWordArray();

 

 

// Perform three tasks in parallel on the source array

Parallel.Invoke(() =>

{

Console.WriteLine("Begin first task...");

GetLongestWord(words);

},// close first Action

 

() =>

{

Console.WriteLine("Begin second task...");

GetMostCommonWords(words);

},//close second Action

 

() =>

{

Console.WriteLine("Begin third task...");

GetCountForWord(words,"species");

}//close third Action

);//close parallel.invoke

 

Console.WriteLine("Returned from Parallel.Invoke");

 

Console.WriteLine("Press any key to exit.");

Console.ReadKey();

}

 

privatestaticstringGetLongestWord(string[] words)

{

var longestWord = (from winwords

orderby w.Length descending

select w).First();

 

Console.WriteLine("Task 1 -- The longest word is {0}", longestWord);

returnlongestWord;

}

 

privatestaticvoidGetMostCommonWords(string[] words)

{

var frequencyOrder = from wordinwords

whereword.Length > 6

group word by word into g

orderby g.Count() descending

select g.Key;

 

var commonWords = frequencyOrder.Take(10);

 

StringBuilder sb =newStringBuilder();

sb.AppendLine("Task 2 -- The most common words are:");

foreach(var vincommonWords)

{

sb.AppendLine(" "+ v);

}

Console.WriteLine(sb.ToString());

}

 

privatestaticvoidGetCountForWord(string[] words,stringterm)

{

var findWord = from wordinwords

whereword.ToUpper().Contains(term.ToUpper())

select word;

 

Console.WriteLine(@"Task 3 -- The word ""{0}"" occurs {1} times.", term, findWord.Count());

}

 

staticstring[] CreateWordArray()

{

strings = System.IO.File.ReadAllText("Origin of the Species.txt");

// Separate string into an array of words, removing some common punctuation.

returns.Split(

newchar[] {' ','\u000A',',','.',';',':','-','_','/'},

StringSplitOptions.RemoveEmptyEntries);

}

}

}

//RESULT:

//Begin second task...

//Begin first task...

//Begin third task...

//Task 2 -- The most common words are:

// species

// selection

// varieties

// natural

// animals

// between

// different

// distinct

// several

// conditions

 

//Task 1 -- The longest word is characteristically

//Task 3 -- The word "species" occurs 1927 times.

//Returned from Parallel.Invoke

//Press any key to exit.

为了更好地控制任务执行或从任务返回值,必须更加显式地使用 Task 对象。

显式创建和运行任务不返回值的任务由System.Threading.Tasks.Task类表示。返回值的任务由System.Threading.Tasks.Task<TResult>类表示,该类从Task继承。

任务对象处理基础结构详细信息,并提供可在任务的整个生存期内从调用线程访问的方法和属性。 例如,可以随时访问任务的Status属性,以确定它是已开始运行、已完成运行、已取消还是引发了异常。 状态由TaskStatus枚举表示。

在创建任务时,你赋予它一个用户委托,该委托封装该任务将执行的代码。 该委托可以表示为命名的委托、匿名方法或 lambda 表达式。 lambda 表达式可以包含对命名方法的调用,如下面的示例所示。

usingSystem;

usingSystem.Threading;

usingSystem.Threading.Tasks;

 

namespaceExplicitTaskDemo

{

classProgram

{

staticvoidMain(string[] args)

{

Thread.CurrentThread.Name ="Main";

// Create a task and supply a user delegate by using a lambda expression.

Task taskA =newTask(() => Console.WriteLine("Hello from taskA."));

// Start the task.

taskA.Start();

// Output a message from the calling thread.

Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);

taskA.Wait();

 

 

 

//Thread.CurrentThread.Name = "Main";

//// Define and run the task.

//Task taskA = Task.Run(() => Console.WriteLine("Hello from taskA."));

//// Output a message from the calling thread.

//Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);

//taskA.Wait();

 

 

 

//Thread.CurrentThread.Name = "Main";

//// Better: Create and start the task in oneOperation.

//Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

//// Output a message from the calling thread.

//Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);

//taskA.Wait();

 

 

 

Console.WriteLine("Press any Key to Exit.");

Console.ReadKey();

}

}

}

//TaskParallel1 RESULT:

//Hello from thread 'Main'.

//Hello from taskA.

//Press any Key to Exit.

你可以用new Task(),也可以用Task.Run(),还可以用Task.Factory.StartNew(),创建并启动一个任务。其中,Task.Run()是首选方法;不必将创建和计划分开并且你需要其他任务创建选项或使用特定计划程序时,或者需要通过 AsyncState 属性将其他状态传递到任务时,使用Task.Factory.StartNew()。

任务创建选项创建任务的大多数 API 提供接受TaskCreationOptions枚举参数。 通过指定下列选项之一,可指示任务计划程序如何在线程池中安排任务计划。

usingSystem;

usingSystem.Threading.Tasks;

 

namespaceTaskCreationOptionsDemo

{

classProgram

{

staticvoidMain(string[] args)

{

var task3 =newTask(() => MyLongRunningMethod(),

TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);

task3.Start();

 

task3.Wait();

 

Console.WriteLine("Press any key to Exit.");

Console.ReadKey();

 

}

staticvoidMyLongRunningMethod()

{

Console.WriteLine("A long, long time ago......");

}

}

}

TaskCreationOptions 参数值

说明

None

未指定任何选项时的默认值。 计划程序将使用其默认试探法来计划任务。

PreferFairness

指定应当计划任务,以使越早创建的任务将更可能越早执行,而越晚创建的任务将更可能越晚执行。

LongRunning

指定该任务表示长时间运行的运算。

AttachedToParent

指定应将任务创建为当前任务(如果存在)的附加子级。 有关更多信息,请参见已附加和已分离的子任务。

DenyChildAttach

指定如果内部任务指定 AttachedToParent 选项,则该任务不会成为附加的子任务。

HideScheduler

指定通过调用特定任务内部的 TaskFactory.StartNew 或 Task<TResult>.ContinueWith 等方法创建的任务的任务计划程序是默认计划程序,而不是正在运行此任务的计划程序。

创建任务延续使用Task.ContinueWith和Task<TResult>.ContinueWith方法可以指定在先行任务完成时要启动的任务。 延续任务的委托已传递了对先行任务的引用,因此它可以检查先行任务的状态,并通过检索Task<TResult>.Result属性的值将先行任务的输出用作延续任务的输入。

var getData = Task.Factory.StartNew(() =>

{

Random rnd =newRandom();

int[] values =newint[100];

for(intctr = 0; ctr <= values.GetUpperBound(0); ctr++)

values[ctr] = rnd.Next();

 

returnvalues;

});

 

 

var processData = getData.ContinueWith((x) =>

{

intn = x.Result.Length;

longsum = 0;

doublemean;

 

for(intctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)

sum += x.Result[ctr];

 

mean = sum / (double)n;

returnTuple.Create(n, sum, mean);

});

 

 

var displayData = processData.ContinueWith((x) =>

{

returnString.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",

x.Result.Item1, x.Result.Item2, x.Result.Item3);

});

 

 

Console.WriteLine(displayData.Result);

//N=100, Total = 108,192,345,466, Mean = 1,081,923,454.66

//Press any key to Exit.

也可以用链式写法:

var displayData = Task.Factory.StartNew(() =>

{

Random rnd =newRandom();

int[] values =newint[100];

for(intctr = 0; ctr <= values.GetUpperBound(0); ctr++)

values[ctr] = rnd.Next();

 

returnvalues;

}).

ContinueWith((x) =>

{

intn = x.Result.Length;

longsum = 0;

doublemean;

 

for(intctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)

sum += x.Result[ctr];

 

mean = sum / (double)n;

returnTuple.Create(n, sum, mean);

}).

ContinueWith((x) =>

{

returnString.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",

x.Result.Item1, x.Result.Item2,

x.Result.Item3);

});

 

Console.WriteLine(displayData.Result);

创建分离的子任务如果在任务中运行的用户代码创建一个新任务,且未指定AttachedToParent选项,则该新任务不采用任何特殊方式与父任务同步。 这种不同步的任务类型称为“分离的嵌套任务”或“分离的子任务”。

var outer = Task.Factory.StartNew(() =>

{

Console.WriteLine("Outer task beginning.");

 

var child = Task.Factory.StartNew(() =>

{

Thread.SpinWait(5000000);

Console.WriteLine("Detached task completed.");

});

 

});

 

outer.Wait();

Console.WriteLine("Outer task completed.");

//The example displays the following output:

//Outer task beginning.

//Outer task completed.

//Detached task completed.

从输出信息看,outer 没有等 child。

创建子任务如果在一个任务中运行的用户代码创建任务时指定了AttachedToParent选项,则该新任务称为父任务的“附加子任务”。 因为父任务隐式地等待所有附加子任务完成,所以你可以使用AttachedToParent选项表示结构化的任务并行。

var parent = Task.Factory.StartNew(() =>

{

Console.WriteLine("Parent task beginning.");

for(intctr = 0; ctr < 10; ctr++)

{

inttaskNo = ctr;

Task.Factory.StartNew((x) =>

{

Thread.SpinWait(5000000);

Console.WriteLine("Attached child #{0} completed.",

x);

},

taskNo, TaskCreationOptions.AttachedToParent);

}

});

 

parent.Wait();

Console.WriteLine("Parent task completed.");

//The example displays the following output:

//Parent task beginning.

//Attached child #9 completed.

//Attached child #0 completed.

//Attached child #8 completed.

//Attached child #1 completed.

//Attached child #3 completed.

//Attached child #7 completed.

//Attached child #4 completed.

//Attached child #5 completed.

//Attached child #2 completed.

//Attached child #6 completed.

//Parent task completed.

等待任务完成System.Threading.Tasks.Task类型和System.Threading.Tasks.Task<TResult>类型提供了Task.Wait和Task<TResult>.Wait方法的若干重载,使你能够等待任务完成。

此外,使用静态Task.WaitAll和Task.WaitAny方法的重载可以等待一批任务中的任一任务或所有任务完成。

通常,会出于以下某个原因等待任务:

主线程依赖于任务计算的最终结果。你必须处理可能从任务引发的异常。应用程序可以在所有任务执行完毕之前终止。 例如,执行 Main(应用程序入口点)中的所有同步代码后,控制台应用程序将立即终止。组合任务Task 类和 Task<TResult> 类提供多种方法,这些方法能够帮助你组合多个任务以实现常见模式,并更好地使用由 C#、Visual Basic 和 F# 提供的异步语言功能。 本节介绍了WhenAll、WhenAny、Delay和FromResult<TResult>方法。

Task.WhenAll 和 Task.WhenAnyusingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Threading;

usingSystem.Threading.Tasks;

 

namespaceTaskWaitAllWaitAnyDemo

{

classProgram

{

staticRandom rand =newRandom();

 

staticvoidMain(string[] args)

{

// Wait on a single task with no timeout specified.

Task taskA = Task.Factory.StartNew(() => DoSomeWork(10000000));

taskA.Wait();

Console.WriteLine("taskA has completed.");

 

 

// Wait on a single task with a timeout specified.

Task taskB = Task.Factory.StartNew(() => DoSomeWork(10000000));

taskB.Wait(100);//Wait for 100 ms.

 

if(taskB.IsCompleted)

Console.WriteLine("taskB has completed.");

else

Console.WriteLine("Timed out before taskB completed.");

 

// Wait for all tasks to complete.

Task[] tasks =newTask[10];

for(inti = 0; i < 10; i++)

{

tasks[i] = Task.Factory.StartNew(() => DoSomeWork(10000000));

}

Task.WaitAll(tasks);

 

// Wait for first task to complete.

Task<double>[] tasks2 =newTask<double>[3];

 

// Try three different approaches to the problem. Take the first one.

tasks2[0] = Task<double>.Factory.StartNew(() => TrySolution1());

tasks2[1] = Task<double>.Factory.StartNew(() => TrySolution2());

tasks2[2] = Task<double>.Factory.StartNew(() => TrySolution3());

 

 

intindex = Task.WaitAny(tasks2);

doubled = tasks2[index].Result;

Console.WriteLine("task[{0}] completed first with result of {1}.", index, d);

 

Console.ReadKey();

}

 

staticvoidDoSomeWork(intval)

{

// Pretend to do something.

Thread.SpinWait(val);

}

 

staticdoubleTrySolution1()

{

inti = rand.Next(1000000);

// Simulate work by spinning

Thread.SpinWait(i);

returnDateTime.Now.Millisecond;

}

staticdoubleTrySolution2()

{

inti = rand.Next(1000000);

// Simulate work by spinning

Thread.SpinWait(i);

returnDateTime.Now.Millisecond;

}

staticdoubleTrySolution3()

{

inti = rand.Next(1000000);

// Simulate work by spinning

Thread.SpinWait(i);

Thread.SpinWait(1000000);

returnDateTime.Now.Millisecond;

}

}

}

//The example displays the following output:

//taskA has completed.

//taskB has completed.

//task[0] completed first with result of 353.

最后一个输出结果是不确定的,因为intindex = Task.WaitAny(tasks2);语句,task2 任务数组中有一个完成,就可以执行该语句下面的语句。

Task.FromResult<TResult>usingSystem;

usingSystem.Collections.Concurrent;

usingSystem.Collections.Generic;

usingSystem.Diagnostics;

usingSystem.Linq;

usingSystem.Net;

usingSystem.Text;

usingSystem.Threading.Tasks;

 

namespaceTaskFromResultDemo

{

/// <summary>

/// Demonstrates how to use Task<TResult>.FromResult to create a task that holds a pre-computed result.

/// </summary>

classProgram

{

// Holds the results of download operations.

staticConcurrentDictionary<string,string> cachedDownloads =newConcurrentDictionary<string,string>();

 

// Asynchronously downloads the requested resource as a string.

publicstaticTask<string> DownloadStringAsync(stringaddress)

{

// First try to retrieve the content from cache.

stringcontent;

if(cachedDownloads.TryGetValue(address,outcontent))

{

returnTask.FromResult<string>(content);

}

 

// If the result was not in the cache, download the

// string and add it to the cache.

returnTask.Run(async () =>

{

content = awaitnewWebClient().DownloadStringTaskAsync(address);

cachedDownloads.TryAdd(address, content);

returncontent;

});

}

 

staticvoidMain(string[] args)

{

// The URLs to download.

string[] urls =newstring[]

{

"http://msdn.microsoft.com",

"http://www.contoso.com",

"http://www.microsoft.com"

};

 

// Used to time download operations.

Stopwatch stopwatch =newStopwatch();

 

// Compute the time required to download the URLs.

stopwatch.Start();

var downloads = from urlinurls

select DownloadStringAsync(url);

Task.WhenAll(downloads).ContinueWith(results =>

{

stopwatch.Stop();

 

// Print the number of characters download and the elapsed time.

Console.WriteLine("Retrieved {0} characters. Elapsed time was {1} ms.",

results.Result.Sum(result => result.Length),

stopwatch.ElapsedMilliseconds);

})

.Wait();

 

// Perform the same operation a second time. The time required

// should be shorter because the results are held in the cache.

stopwatch.Restart();

downloads = from urlinurls

select DownloadStringAsync(url);

Task.WhenAll(downloads).ContinueWith(results =>

{

stopwatch.Stop();

 

// Print the number of characters download and the elapsed time.

Console.WriteLine("Retrieved {0} characters. Elapsed time was {1} ms.",

results.Result.Sum(result => result.Length),

stopwatch.ElapsedMilliseconds);

})

.Wait();

 

Console.WriteLine("Press any key to Exit.");

Console.ReadKey();

}

}

}

//The example displays the following output:

//Retrieved 45462 characters. Elapsed time was 23734 ms.

//Retrieved 45462 characters. Elapsed time was 0 ms.

//Press any key to Exit.

任务中的异常处理当某个任务抛出一个或多个异常时,异常包装在AggregateException异常中。 该异常传播回与该任务联接的线程,通常该线程正在等待该任务完成或该线程访问 Result 属性。此行为用于强制实施 .NET Framework 策略 - 默认所有未处理的异常应终止进程。

可以通过将Wait、WaitAll或WaitAny方法,以及Result属性放入try/catch块中来处理异常。

捕获System.AggregateException,然后检查其InnerExceptions以查看是否存在任何可由程序代码处理的异常。如下代码所示:

staticvoidHandleExceptions()

{

// Assume this is a user-entered string.

stringpath =@"C:\";

 

// Use this line to throw UnauthorizedaccessException, which we handle.

Task<string[]> task1 = Task<string[]>.Factory.StartNew(() => GetAllFiles(path));

 

// Use this line to throw an exception that is not handled.

// Task task1 = Task.Factory.StartNew(() => { throw new IndexOutOfRangeException(); } );

try

{

task1.Wait();

}

catch (AggregateException ae)

{

ae.Handle((x) =>

{

if (x is UnauthorizedAccessException) // This we know how to handle.

{

Console.WriteLine("Youdonot have permission to access all foldersinthispath.");

Console.WriteLine("See your network administrator ortryanother path.");

return true;

}

return false; // Let anything else stop theapplication.

});

 

}

 

Console.WriteLine("task1 has completed.");

}

 

static string[] GetAllFiles(string str)

{

// Should throw an AccessDenied exception onVista.

return System.IO.Directory.GetFiles(str, "*.txt", System.IO.SearchOption.AllDirectories);

}

在此示例中,捕获System.AggregateException,但不尝试处理任何其内部异常。 而是使用Flatten方法从任何嵌套的AggregateException实例中提取内部异常,并再次引发直接包含所有内部未处理异常的单个AggregateException。 展平异常将使其更便于供客户端代码处理。

staticvoidRethrowAllExceptions()

{

// Assume this is a user-entered string.

stringpath =@"C:\";

 

 

Task<string[]>[] tasks = new Task<string[]>[3];

tasks[0] = Task<string[]>.Factory.StartNew(() => GetAllFiles(path));

tasks[1] = Task<string[]>.Factory.StartNew(() => GetValidExtensions(path));

tasks[2] = Task<string[]>.Factory.StartNew(() => new string[10]);

 

 

//int index = Task.WaitAny(tasks2);

//double d = tasks2[index].Result;

try

{

Task.WaitAll(tasks);

}

catch (AggregateException ae)

{

throw ae.Flatten();

}

 

Console.WriteLine("task1 has completed.");

}

 

static string[] GetValidExtensions(string path)

{

if (path == @"C:\")

throw new ArgumentException("The system rootisnot a valid path.");

 

returnnewstring[10];

}

取消任务Task 类支持协作取消,并与 .NET Framework 4 中新增的System.Threading.CancellationTokenSource类和System.Threading.CancellationToken类完全集成。

创建任务的大多数 API 提供接受CancellationToken参数。

var tokenSource2 =newCancellationTokenSource();

CancellationToken ct = tokenSource2.Token;

 

var task = Task.Factory.StartNew(() =>

{

// Were we already canceled?

ct.ThrowIfCancellationRequested();

 

boolmoreToDo =true;

while(moreToDo)

{

// Poll on this property if you have to do

// other cleanup before throwing.

if(ct.IsCancellationRequested)

{

// Clean up here, then...

ct.ThrowIfCancellationRequested();

}

}

}, tokenSource2.Token);// Pass same token to StartNew.

 

tokenSource2.Cancel();

 

// Just continue on this thread, or Wait/WaitAll with try-catch:

try

{

task.Wait();

}

catch(AggregateException e)

{

foreach(var vine.InnerExceptions)

Console.WriteLine(e.Message +" "+ v.Message);

}

TaskFactory 类

TaskFactory类提供静态方法,这些方法封装了用于创建和启动任务和延续任务的一些常用模式。

最常用模式为StartNew,它在一个语句中创建并启动任务。从多个先行任务创建延续任务时,请使用ContinueWhenAll方法或ContinueWhenAny方法,或者它们在Task<TResult>类中的等效方法。 有关更多信息,请参见延续任务。若要在Task或Task<TResult>实例中封装异步编程模型BeginX和EndX方法,请使用FromAsync方法。默认的TaskFactory可作为Task类或Task<TResult>类上的静态属性访问。 你还可以直接实例化TaskFactory并指定各种选项,包括CancellationToken、TaskCreationOptions选项、TaskContinuationOptions选项或TaskScheduler。 创建任务工厂时所指定的任何选项将应用于它创建的所有任务,除非Task是通过使用TaskCreationOptions枚举创建的(在这种情况下,任务的选项重写任务工厂的选项)。

无委托的任务在某些情况下,可能需要使用Task封装由外部组件(而不是你自己的用户委托)执行的某个异步操作。 如果该操作基于异步编程模型 Begin/End 模式,你可以使用FromAsync方法。 如果不是这种情况,你可以使用TaskCompletionSource<TResult>对象将该操作包装在任务中,并因而获得 Task 可编程性的一些好处,例如对异常传播和延续的支持。

在许多方案中,启用一个Task<TResult>来表示外部异步操作非常有用。 出于此目的,提供了TaskCompletionSource<TResult>。 它允许创建可以分发到使用者的任务,这些使用者可以同其他情况下一样使用该任务的成员。 但是,与大多数任务不同,TaskCompletionSource创建的任务的状态由TaskCompletionSource上的方法显式控制。 这使得要传播到基础任务的外部异步操作能够完成。 分离还确保使用者没有访问对应的TaskCompletionSource时不能转换状态。

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Diagnostics;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Threading;

usingSystem.Threading.Tasks;

 

namespaceTaskCompletionSourceDemo

{

classProgram

{

// Demonstrated features:

// TaskCompletionSource ctor()

// TaskCompletionSource.SetResult()

// TaskCompletionSource.SetException()

// Task.Result

// Expected results:

// The attempt to get t1.Result blocks for ~1000ms until tcs1 gets signaled. 15 is printed out.

// The attempt to get t2.Result blocks for ~1000ms until tcs2 gets signaled. An exception is printed out.

// Documentation:

// http://msdn.microsoft.com/en-us/library/dd449199(VS.100).aspx

staticvoidMain(string[] args)

{

TaskCompletionSource<int> tcs1 =newTaskCompletionSource<int>();

Task<int> t1 = tcs1.Task;

 

// Start a background task that will complete tcs1.Task

Task.Factory.StartNew(() =>

{

Thread.Sleep(1000);

tcs1.SetResult(15);

});

 

// The attempt to get the result of t1 blocks the current thread until the completion source gets signaled.

// It should be a wait of ~1000 ms.

Stopwatch sw = Stopwatch.StartNew();

intresult = t1.Result;

sw.Stop();

 

Console.WriteLine("(ElapsedTime={0}): t1.Result={1} (expected 15) ", sw.ElapsedMilliseconds, result);

 

// ------------------------------------------------------------------

 

// Alternatively, an exception can be manually set on a TaskCompletionSource.Task

TaskCompletionSource<int> tcs2 =newTaskCompletionSource<int>();

Task<int> t2 = tcs2.Task;

 

// Start a background Task that will complete tcs2.Task with an exception

Task.Factory.StartNew(() =>

{

Thread.Sleep(1000);

tcs2.SetException(newInvalidOperationException("SIMULATED EXCEPTION"));

});

 

// The attempt to get the result of t2 blocks the current thread until the completion source gets signaled with either a result or an exception.

// In either case it should be a wait of ~1000 ms.

sw = Stopwatch.StartNew();

try

{

result = t2.Result;

 

Console.WriteLine("t2.Result succeeded. THIS WAS NOT EXPECTED.");

 

Console.WriteLine("Press any key to Exit.");

Console.ReadKey();

}

catch(AggregateException e)

{

Console.Write("(ElapsedTime={0}): ", sw.ElapsedMilliseconds);

Console.WriteLine("The following exceptions have been thrown by t2.Result: (THIS WAS EXPECTED)");

for(intj = 0; j < e.InnerExceptions.Count; j++)

{

Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());

}

 

Console.WriteLine("Press any key to Exit.");

Console.ReadKey();

}

}

}

}

相关数据结构TPL 有几种在并行和顺序方案中都有用的新公共类型。 它们包括System.Collections.Concurrent命名空间中的一些线程安全的、快速且可缩放的集合类,还包括一些新的同步类型(例如System.Threading.Semaphore和System.Threading.ManualResetEventSlim),对特定类型的工作负荷而言,这些新同步类型比旧的同步类型效率更高。 .NET Framework 4 中的其他新类型(例如System.Threading.Barrier和System.Threading.SpinLock)提供了早期版本中未提供的功能。

参考资料Microsoft Developer Network 并行编程Microsft Developer Network 任务并行  

下载 Demo

下载 Samples for Parallel Programming with .net framework

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有