Task C# 多线程和异步模型 TPL模型

 

Task,异步,多线程简单总结

1,如何把一个异步封装为Task异步

Task.Factory.FromAsync

对老的一些异步模型封装为Task

TaskCompletionSource

更通用,在回调中只要SetResult()一下就表示Task结束了,用它可以将各种异步回调封装为Task

2,一个可以await的可以返回Task的Async结尾的异步方法从哪里开始进入另一个线程的

如果是对BeginXXX EndXXX的APM异步模型封装的,从进入XXXAsync方法后直到BeginXXX前还在调用方法的线程内,然后无阻塞的等待回调,当等打完后,就相当于在回调中了,此时可能进入了另一个线程,其他也是类似的,从底层方法异步的地方开始异步的,而不是一进入方法就到了另一个线程了,所以进入方法后写很多CPU密集程序是会阻塞的

3,如何立刻扔到另一个线程

Task.Run或者Task.Factory.StartNew可以直接从另一个线程开始,可以直接把XXXAsync方法扔进去

4,一个约定

纯C#框架或者类库提供的Async结尾的可await方法,里面一定有无阻塞异步的实现,否则没必要搞成异步的,就比如newtonsoft.json的异步序列化方法被标识为已过时。

5,Task外面如何告诉Task该取消了

CancellationTokenSource

其实和一个Flag差不多,只不过封装了一些方法以异常类

6,很多情况下要先学会同步才能并发

7,Task.Run Task.Start Task.Factory.StartNew 等都是使用线程池的线程

8,IO异步底层为IRP消息,通常是和硬件交互所使用的消息机制,当然那是驱动层的事情,IO异步当然也就是无阻塞的,等IRP消息回来就是回调

9,UI线程

最终会渲染界面的代码一定要在UI线程执行,可以使用比如winform的control.Invoke ,wpf的Dispatcher

一旦开始并发了,还有很多很多的坑

【C#】43. TPL基础——Task初步
2016年12月11日 20:56:10

阅读数:1379

从这篇文章开始,我想直接进入关于Task的一些内容,有时间再回顾Threadpool的相关内容。

我一开始接触Task就觉得他和Thread很像,都是开新的线程。但是两者有很多区别,其中比较明显的是:Task创建的是线程池任务,而Thread默认创建的是前台任务。

同Thread一样,Task可以使用lambda表达式来构造action,作为Task的构造函数参数。如下:

1、先定义一个函数TaskMethod,他接受name作为字符串参数。

  1. static void TaskMethod(string name)
  2. {
  3. Console.WriteLine("Task {0} 运行在线程id为{1}的线程上. 是否是线程池中线程?:{2}",
  4. name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
  5. }

2、新建Task实例,并且Start():

  1. var t1 = new Task(() => TaskMethod("Task 1"));
  2. t1.Start();

因为Task接受无参数和返回值的Action作为构造器参数,因此此处可以使用如上的lambda表达式,在表达式中传参"Task 1"。

运行结果如下:

可以很明显的看出,该Task(t1)运行在线程池中。

必须要指出的是,线程池一般只运行执行时间较短的异步操作,需要长时间执行的操作尽量不要使用线程池。

除了上面这种开Task的方法,还有两种常见的用法,分别是 Task.Run() 和 Task.Factory.StartNew()。两者的区别在于后者能传入一些额外参数,以丰富Task的运行选项。例如:

  1. Task.Run(() => TaskMethod("Task 3"));
  2. Task.Factory.StartNew(() => TaskMethod("Task 4"));
  3. Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

第一句直接调用静态方法Task.Run(),lambda表达式作为参数(Action),不需要再调用Start()方法,立即执行。

第二句则使用了Task.Factory.StartNew()默认方法,最后一句加入了选项“LongRunning”,意味着该任务将长时间运行,因此他不是在线程池中执行。

结果如下:

注意:Task的运行有一定的随机性,开始次序会有变化!

22 C# 第十八章 TPL 并行编程
2013年08月12日 09:24:08

阅读数:5175
C# TPL(Task Parallel Library) 并行编程是.Net4 为多线程编程引入的新的API。因为并行编程涉及到的知识非常广泛,这里只是简单的把.Net 4中TPL的用法总结了一下。

一: Task 线程的基本使用

关于Action委托: 它是 .Net 定义的一种委托类型。
public delegate void Action():  封装一个方法,该方法不具有参数并且不返回值。
public delegate void Action<in T>(T obj):  封装一个方法,该方法只有一个参数并且不返回值。
...  ...

可以使用此委托以参数形式传递方法,而不用显式声明自定义的委托。 封装的方法必须与此委托定义的方法签名相对应。
http://msdn.microsoft.com/zh-cn/library/vstudio/system.action.aspx

光看语言描述理解起来有点费劲。看MSDN给的例子,把自定义的委托和Action比较一下就清楚多了。

两个小例子:

使用委托的例子

  1. using System;
  2. using System.Windows.Forms;
  3. public delegate void ShowValue();
  4. public class Name
  5. {
  6. private string instanceName;
  7. public Name(string name)
  8. {
  9. this.instanceName = name;
  10. }
  11. public void DisplayToConsole()
  12. {
  13. Console.WriteLine(this.instanceName);
  14. }
  15. public void DisplayToWindow()
  16. {
  17. MessageBox.Show(this.instanceName);
  18. }
  19. }
  20. public class testTestDelegate
  21. {
  22. public static void Main()
  23. {
  24. Name testName = new Name("Koani");
  25. ShowValue showMethod = testName.DisplayToWindow;
  26. showMethod();
  27. }
  28. }

使用 action的例子

  1. using System;
  2. using System.Windows.Forms;
  3. public class Name
  4. {
  5. private string instanceName;
  6. public Name(string name)
  7. {
  8. this.instanceName = name;
  9. }
  10. public void DisplayToConsole()
  11. {
  12. Console.WriteLine(this.instanceName);
  13. }
  14. public void DisplayToWindow()
  15. {
  16. MessageBox.Show(this.instanceName);
  17. }
  18. }
  19. public class testTestDelegate
  20. {
  21. public static void Main()
  22. {
  23. Name testName = new Name("Koani");
  24. Action showMethod = testName.DisplayToWindow;
  25. showMethod();
  26. }
  27. }

这里把Action 看成了一种特殊的委托,没有参数也没有返回值,这样理解起来就简单了。

关于 Task 的简单介绍
更确切的说它是把线程的概念抽象出来了。这里它更关心的是线程中工作的内容。而把创建线程,重用线程或释放线程等平台相关的工作留给了系统。它更贴近与System.Threading.ThreadPool。一个由系统管理的ThreadPool。

使用 Task 创建线程

一个简单的线程使用的例子

http://msdn.microsoft.com/zh-cn/library/vstudio/1h2f2459.aspx

  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. class StartNewDemo
  5. {
  6. static void Main()
  7. {
  8. Action<object> action = (object obj) =>
  9. {
  10. Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId);
  11. };
  12. // Construct an unstarted task
  13. Task t1 = new Task(action, "alpha");
  14. // Cosntruct a started task
  15. Task t2 = Task.Factory.StartNew(action, "beta");
  16. // Block the main thread to demonstate that t2 is executing
  17. t2.Wait();
  18. // Launch t1
  19. t1.Start();
  20. Console.WriteLine("t1 has been launched. (Main Thread={0})", Thread.CurrentThread.ManagedThreadId);
  21. // Wait for the task to finish.
  22. // You may optionally provide a timeout interval or a cancellation token
  23. // to mitigate situations when the task takes too long to finish.
  24. t1.Wait();
  25. // Construct an unstarted task
  26. Task t3 = new Task(action, "gamma");
  27. // Run it synchronously
  28. t3.RunSynchronously();
  29. // Although the task was run synchrounously, it is a good practice to wait for it which observes for
  30. // exceptions potentially thrown by that task.
  31. t3.Wait();
  32. Console.ReadKey();
  33. }
  34. }

程序说明:

API: Task.Factory
     创建任务并立即启动任务。
     创建在一组任务中的任意或全部任务完成后启动的任务延续项
     创建表示开始/结束方法对的任务,这些方法采用异步编程模型。

Task.RunSynchronously
     任务只可以启动并运行一次。 再次计划任务的尝试将导致异常。通过 RunSynchronously 执行的任务将与当前 TaskScheduler 关联。
     如果目标计划程序不支持当前线程上运行此任务,则在计划程序上计划执行该任务,当前线程会阻塞,直到该任务完成执行。

从线程中返回结果

线程常用的成员
Status: 此任务实例的当前状态 TaskStatus(http://msdn.microsoft.com/zh-cn/library/vstudio/system.threading.tasks.taskstatus.aspx)

IsCompleted: true ,如果任务已完成;否则 false。它不管任务是否出错。

Id: System.Int32类型, 系统分配给此任务实例的一个整数。任务 ID 分配在需要时并不一定表示在任务实例创建的顺序。

AsyncState  它允许跟踪额外的数据。例如,假定多个任务要计算一个List<T>的值。为了将结果放到列表中正确的位置,一个办法是将准备包含结果的那个列表索引存储到AsyncState中。这样一来,在任务结束后,代码可使用AsyncState先转型为int 访问列表中特定索引的位置。这个理解的还不是很透彻,回头应该找个例子看看。

ContinueWith(): 创建一个在目标 Task 完成时异步执行的延续任务。

一个实例

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. // Demonstrates how to associate state with task continuations.
  6. class ContinuationState
  7. {
  8. // Simluates a lengthy operation and returns the time at which
  9. // the operation completed.
  10. public static DateTime DoWork()
  11. {
  12. // Simulate work by suspending the current thread
  13. // for two seconds.
  14. Console.WriteLine("Thread = {0} sleep 2 seconds", Task.CurrentId);
  15. Thread.Sleep(2000);
  16. // Return the current time.
  17. return DateTime.Now;
  18. }
  19. static void Main(string[] args)
  20. {
  21. Action action = () =>
  22. {
  23. DoWork();
  24. };
  25. Task<DateTime> t = new Task<DateTime>(DoWork);
  26. t.Start();
  27. Console.WriteLine("Date = {0}", t.Result);
  28. t.Wait();
  29. Console.ReadKey();
  30. }
  31. }

二: Task上的未处理异常

关注点是如何从一个不同的线程中引发的未处理的异常。在Task执行期间产生的未处理的异常会被禁止(suppressed),直到调用某个任务完成(task complete)成员: Wait(), Result, Task.WaitAll(),或者Task.WaitAny()。上述每个成员都会引发任务执行期间发生的任何未处理的异常。

Wait引发异常的例子

  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. namespace Thread_Task_Sample_Exception_Simple
  5. {
  6. class Program
  7. {
  8. static void Main(string[] args)
  9. {
  10. Action<object> action = (object obj) =>
  11. {
  12. Console.WriteLine("Task={0}, obj={1}, Thread={2}  Throw Exception", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId);
  13. throw (new Exception());
  14. };
  15. // Cosntruct a started task
  16. Task t = Task.Factory.StartNew(action, "A");
  17. for (int i = 0; i < 50; i++)
  18. {
  19. Console.Write(".");
  20. Thread.Sleep(200);
  21. }
  22. Console.WriteLine();
  23. try
  24. {
  25. // Block the main thread to demonstate that t2 is executing
  26. t.Wait();
  27. }
  28. catch (Exception ex)
  29. {
  30. Console.WriteLine("Task.Wait cause an exception, We caught it");
  31. }
  32. Console.ReadKey();
  33. }
  34. }
  35. }

使用 ContinueWith ()

  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. class ContinuationSimpleDemo
  5. {
  6. // Demonstrated features:
  7. //      Task.Factory
  8. //      Task.ContinueWith()
  9. //      Task.Wait()
  10. // Expected results:
  11. //      A sequence of three unrelated tasks is created and executed in this order - alpha, beta, gamma.
  12. //      A sequence of three related tasks is created - each task negates its argument and passes is to the next task: 5, -5, 5 is printed.
  13. //      A sequence of three unrelated tasks is created where tasks have different types.
  14. // Documentation:
  15. static void Main()
  16. {
  17. Action<string> action =
  18. (str) =>
  19. Console.WriteLine("Task={0}, str={1}, Thread={2}", Task.CurrentId, str, Thread.CurrentThread.ManagedThreadId);
  20. // Creating a sequence of action tasks (that return no result).
  21. Console.WriteLine("Creating a sequence of action tasks (that return no result)");
  22. Task.Factory.StartNew(() => action("alpha"))
  23. .ContinueWith(antecendent => action("beta"))        // Antecedent data is ignored
  24. .ContinueWith(antecendent => action("gamma"))
  25. .Wait();
  26. Func<int, int> negate =
  27. (n) =>
  28. {
  29. Console.WriteLine("Task={0}, n={1}, -n={2}, Thread={3}", Task.CurrentId, n, -n, Thread.CurrentThread.ManagedThreadId);
  30. return -n;
  31. };
  32. // Creating a sequence of function tasks where each continuation uses the result from its antecendent
  33. Console.WriteLine("\nCreating a sequence of function tasks where each continuation uses the result from its antecendent");
  34. Task<int>.Factory.StartNew(() => negate(5))
  35. .ContinueWith(antecendent => negate(antecendent.Result))     // Antecedent result feeds into continuation
  36. .ContinueWith(antecendent => negate(antecendent.Result))
  37. .Wait();
  38. // Creating a sequence of tasks where you can mix and match the types
  39. Console.WriteLine("\nCreating a sequence of tasks where you can mix and match the types");
  40. Task<int>.Factory.StartNew(() => negate(6))
  41. .ContinueWith(antecendent => action("x"))
  42. .ContinueWith(antecendent => negate(7))
  43. .Wait();
  44. Console.ReadKey();
  45. }
  46. }

使用ContinueWith 如果在程序中出现异常,后面后续的处理函数可以帮助程序把信息清理干净。

三: 取消任务

野蛮终止的问题:在.Net3.5 或之前的版本,其实并没有怎么支持线程的取消,相反采取的是一种中断的方式。.Net4 中基于PLINQ和TPL的API只支持一种取消请求的方式,协作式取消 -- 目标Task可自行决定是否满足取消请求。

取消任务的一个实例代码:

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. public class Example
  6. {
  7. public static void Main()
  8. {
  9. var tokenSource = new CancellationTokenSource();
  10. var token = tokenSource.Token;
  11. // Store references to the tasks so that we can wait on them and
  12. // observe their status after cancellation.
  13. Task t;
  14. var tasks = new ConcurrentBag<Task>();
  15. Console.WriteLine("Press any key to begin tasks...");
  16. Console.WriteLine("To terminate the example, press 'c' to cancel and exit...");
  17. Console.ReadKey();
  18. Console.WriteLine();
  19. // Request cancellation of a single task when the token source is canceled.
  20. // Pass the token to the user delegate, and also to the task so it can
  21. // handle the exception correctly.
  22. t = Task.Factory.StartNew(() => DoSomeWork(1, token), token);
  23. Console.WriteLine("Task {0} executing", t.Id);
  24. tasks.Add(t);
  25. // Request cancellation of a task and its children. Note the token is passed
  26. // to (1) the user delegate and (2) as the second argument to StartNew, so
  27. // that the task instance can correctly handle the OperationCanceledException.
  28. t = Task.Factory.StartNew(() =>
  29. {
  30. // Create some cancelable child tasks.
  31. Task tc;
  32. for (int i = 3; i <= 10; i++)
  33. {
  34. // For each child task, pass the same token
  35. // to each user delegate and to StartNew.
  36. tc = Task.Factory.StartNew(iteration => DoSomeWork((int)iteration, token), i, token);
  37. Console.WriteLine("Task {0} executing", tc.Id);
  38. tasks.Add(tc);
  39. // Pass the same token again to do work on the parent task.
  40. // All will be signaled by the call to tokenSource.Cancel below.
  41. DoSomeWork(2, token);
  42. }
  43. }, token);
  44. Console.WriteLine("Task {0} executing", t.Id);
  45. tasks.Add(t);
  46. // Request cancellation from the UI thread.
  47. if (Console.ReadKey().KeyChar == 'c')
  48. {
  49. tokenSource.Cancel();
  50. Console.WriteLine("\nTask cancellation requested.");
  51. // Optional: Observe the change in the Status property on the task.
  52. // It is not necessary to wait on tasks that have canceled. However,
  53. // if you do wait, you must enclose the call in a try-catch block to
  54. // catch the TaskCanceledExceptions that are thrown. If you do
  55. // not wait, no exception is thrown if the token that was passed to the
  56. // StartNew method is the same token that requested the cancellation.
  57. }
  58. try
  59. {
  60. Task.WaitAll(tasks.ToArray());
  61. }
  62. catch (AggregateException e)
  63. {
  64. Console.WriteLine("\nAggregateException thrown with the following inner exceptions:");
  65. // Display information about each exception.
  66. foreach (var v in e.InnerExceptions)
  67. {
  68. if (v is TaskCanceledException)
  69. Console.WriteLine("   TaskCanceledException: Task {0}",
  70. ((TaskCanceledException)v).Task.Id);
  71. else
  72. Console.WriteLine("   Exception: {0}", v.GetType().Name);
  73. }
  74. Console.WriteLine();
  75. }
  76. // Display status of all tasks.
  77. foreach (var task in tasks)
  78. Console.WriteLine("Task {0} status is now {1}", task.Id, task.Status);
  79. Console.ReadKey();
  80. }
  81. static void DoSomeWork(int taskNum, CancellationToken ct)
  82. {
  83. // Was cancellation already requested?
  84. if (ct.IsCancellationRequested == true)
  85. {
  86. Console.WriteLine("Task {0} was cancelled before it got started.", taskNum);
  87. ct.ThrowIfCancellationRequested();
  88. }
  89. int maxIterations = 100;
  90. // NOTE!!! A "TaskCanceledException was unhandled
  91. // by user code" error will be raised here if "Just My Code"
  92. // is enabled on your computer. On Express editions JMC is
  93. // enabled and cannot be disabled. The exception is benign.
  94. // Just press F5 to continue executing your code.
  95. for (int i = 0; i <= maxIterations; i++)
  96. {
  97. // Do a bit of work. Not too much.
  98. var sw = new SpinWait();
  99. for (int j = 0; j <= 100; j++)
  100. sw.SpinOnce();
  101. if (ct.IsCancellationRequested)
  102. {
  103. Console.WriteLine("Task {0} cancelled", taskNum);
  104. ct.ThrowIfCancellationRequested();
  105. }
  106. }
  107. }
  108. }

四: 并行迭代  Task.Parallel

API 会判定同时执行多少个线程效率最高。效率由一个爬山算法来决定。

一个parallel并行的例子

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. using System.Text;
  5. namespace Thread_Task_Sample_Parallel
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
  11. int[] data = new int[100];
  12. int i = 0;
  13. for (i = 0; i < data.Length; i++)
  14. {
  15. data[i] = i;
  16. Console.Write("{0} ", data[i]);
  17. }
  18. Console.WriteLine(" \n ");
  19. Console.WriteLine("\nParallel running ... ... \n");
  20. Parallel.For(0, 100, (j)=>
  21. {
  22. System.Threading.Thread.Sleep(1000);
  23. data[j] = data[j] * 2;
  24. Console.Write("{0} ", data[j]);
  25. });
  26. Console.WriteLine("\n\nParallel end ... ... \n");
  27. Console.WriteLine(" \n ");
  28. for (i = 0; i < data.Length; i++)
  29. {
  30. Console.Write("{0} ", data[i]);
  31. }
  32. Console.WriteLine(" \n ");
  33. Console.ReadKey();
  34. }
  35. }
  36. }

测试结果:

实例代码

 
 
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangzhiyu1980/article/details/9915431
 

TPL 和传统 .NET 异步编程一
2010年05月28日 17:47:00

阅读数:3715

TPL即任务并行库,是.NET Framework 4版本中的新鲜物,是System.Threading 和 System.Threading.Tasks 命名空间中的一组公共类型和 API。TPL 的目的在于简化向应用程序中添加并行性和并发性的过程,从而提高开发人员的工作效率。 TPL 会动态地按比例调节并发程度,以便最有效地使用所有可用的处理器。此外,TPL 还处理工作分区、ThreadPool 上的线程调度、取消支持、状态管理以及其他低级别的细节操作。通过使用 TPL,您可以在将精力集中于程序要完成的工作,同时最大程度地提高代码的性能。

TPL涉及的内容很多,在这里主要先介绍一下TPL与传统的.NET异步编程之间的关系。在以前的.NET Framework版本中,它 提供以下两种执行 I/O 绑定和计算绑定异步操作的标准模式:

  • 异步编程模型 (APM),在该模型中异步操作由一对 Begin/End 方法(如 FileStream.BeginRead 和 Stream.EndRead)表示。
  • 基于事件的异步模式 (EAP),在该模式中异步操作由名为“操作名称Async”和“操作名称Completed”的方法/事件对(例如 WebClient.DownloadStringAsync 和 WebClient.DownloadStringCompleted)表示。(EAP 是在 .NET Framework 2.0 版中引入的)。

而任务并行库 (TPL) 可通过各种方式与任一异步模式结合使用。可以将 APM 和 EAP 操作以 Task 的形式向库使用者公开,或者可以公开 APM 模式,但使用 Task 对象在内部实现它们。在这两种方案中,通过使用 Task 对象,可以简化代码并利用以下有用的功能:

  • 在任务启动后,可以随时以任务延续的形式注册回调。
  • 通过使用 ContinueWhenAll 和 ContinueWhenAny 方法或者 WaitAll 方法或 WaitAny 方法,协调多个为了响应 Begin_ 方法而执行的操作。
  • 在同一 Task 对象中封装异步 I/O 绑定和计算绑定操作。
  • 监视 Task 对象的状态。
  • 使用 TaskCompletionSource<TResult> 将操作的状态封送到 Task 对象。

下面介绍一下TPL是如何与传统的.NET 异步相互结合在一起使用的。

在任务中包装 APM 操作

System.Threading.Tasks.TaskFactory 和 System.Threading.Tasks.TaskFactory<TResult> 类都提供了 FromAsync 方法的一些重载,这些重载使您可以在一个 Task 实例或 Task<TResult> 实例中封装一个 APM Begin/End 方法对。各种重载可容纳任何具有零到三个输入参数的 Begin/End 方法对。
对于具有返回值的 End 方法(在 Visual Basic 中为 Function)的对,在创建 Task<TResult> 的 TaskFactory<TResult> 中使用这些方法。对于返回 void 的 End 方法(在 Visual Basic 中为 Sub),在创建 Task 的 TaskFactory 中使用这些方法。
对于 Begin 方法有三个以上的参数或包含 ref 或 out 参数的少数情况,提供了仅封装 End 方法的附加 FromAsync 重载。
下面的代码示例演示与 FileStream.BeginRead 和 FileStream.EndRead 方法匹配的 FromAsync 重载的签名。此重载采用三个输入参数,如下所示。

  1. public Task<TResult> FromAsync<TArg1, TArg2, TArg3>(
  2. Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, //BeginRead
  3. Func<IAsyncResult, TResult> endMethod, //EndRead
  4. TArg1 arg1, // the byte[] buffer
  5. TArg2 arg2, // the offset in arg1 at which to start writing data
  6. TArg3 arg3, // the maximum number of bytes to read
  7. object state // optional state information
  8. )

第一个参数是与 FileStream.BeginRead 方法的签名匹配的 Func<T1, T2, T3, T4, T5, TResult> 委托。第二个参数是采用 IAsyncResult 并返回 TResult 的 Func<T, TResult> 委托。由于 EndRead 返回一个整数,因此编译器将 TResult 的类型推断为 Int32,将任务的类型推断为 Task<Int32>。最后四个参数等同于 FileStream.BeginRead 方法中的那些参数:

  • 在其中存储文件数据的缓冲区。
  • 缓冲区中开始写入数据的偏移量。
  • 要从文件中读取的最大数据量。
  • 用于存储要传递给回调的用户定义状态数据的可选对象。

将 ContinueWith 用于回调功能

如果需要访问文件中的数据,而不只是访问字节数,则使用 FromAsync 方法是不够的。而应当使用 Task<String>,其 Result 属性包含文件数据。可以通过向原始任务添加延续任务来执行此操作。延续任务执行 AsyncCallback 委托通常执行的工作。当前面的任务完成并且数据缓冲区已填充时,会调用它。(FileStream 对象应在返回之前关闭)。

下面的示例演示如何返回 Task<String>,它封装了 FileStream 类的 BeginRead/EndRead 对。

  1. const int MAX_FILE_SIZE = 14000000;
  2. public static Task<string> GetFileStringAsync(string path)
  3. {
  4. FileInfo fi = new FileInfo(path);
  5. byte[] data = null;
  6. data = new byte[fi.Length];
  7. FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, data.Length, true);
  8. //Task<int> returns the number of bytes read
  9. Task<int> task = Task<int>.Factory.FromAsync(
  10. fs.BeginRead, fs.EndRead, data, 0, data.Length, null);
  11. // It is possible to do other work here while waiting
  12. // for the antecedent task to complete.
  13. // ...
  14. // Add the continuation, which returns a Task<string>.
  15. return task.ContinueWith((antecedent) =>
  16. {
  17. fs.Close();
  18. // Result = "number of bytes read" (if we need it.)
  19. if (antecedent.Result < 100)
  20. {
  21. return "Data is too small to bother with.";
  22. }
  23. else
  24. {
  25. // If we did not receive the entire file, the end of the
  26. // data buffer will contain garbage.
  27. if (antecedent.Result < data.Length)
  28. Array.Resize(ref data, antecedent.Result);
  29. // Will be returned in the Result property of the Task<string>
  30. // at some future point after the asynchronous file I/O operation completes.
  31. return new UTF8Encoding().GetString(data);
  32. }
  33. });
  34. }

然后可以按如下所示调用该方法。

  1. Task<string> t = GetFileStringAsync(path);
  2. // Do some other work:
  3. // ...
  4. try
  5. {
  6. Console.WriteLine(t.Result.Substring(0, 500));
  7. }
  8. catch (AggregateException ae)
  9. {
  10. Console.WriteLine(ae.InnerException.Message);
  11. }

Task.Delay() 和 Thread.Sleep() 区别

1、Thread.Sleep 是同步延迟,Task.Delay异步延迟。

2、Thread.Sleep 会阻塞线程,Task.Delay不会。

3、Thread.Sleep不能取消,Task.Delay可以。

4. Task.Delay() 比 Thread.Sleep() 消耗更多的资源,但是Task.Delay()可用于为方法返回Task类型;或者根据CancellationToken取消标记动态取消等待

5. Task.Delay() 实质创建一个运行给定时间的任务, Thread.Sleep() 使当前线程休眠给定时间。

Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别的更多相关文章

  1. Task.Delay() 和 Thread.Sleep() 区别

    1.Thread.Sleep 是同步延迟,Task.Delay异步延迟. 2.Thread.Sleep 会阻塞线程,Task.Delay不会. 3.Thread.Sleep不能取消,Task.Dela ...

  2. Python之路(第三十六篇)并发编程:进程、同步异步、阻塞非阻塞

    一.理论基础 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有内容都是围绕进程的概念展开的. 即使可以利用的cpu只有一个(早期的 ...

  3. 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换

    [源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...

  4. 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换

    经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...

  5. 多线程之异步编程: 经典和最新的异步编程模型,async与await

    经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...

  6. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

  7. 【转】深入浅出异步I/O模型

    转自:http://pengpeng.iteye.com/blog/868643 从上篇文章的介绍我们知道linux内核根据TCP/IP网络模型,给我们隐藏了传输层以下的网络传输细节,我们的网络应用程 ...

  8. WinSock 异步I/O模型-3

    重叠I/O(Overlapped I/O) 在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于之前讲过的三种.重叠模型的基本设计原理便是让应用程序使用一 ...

  9. WinSock 异步I/O模型-2

    事件选择(WSAEventSelect): WSAEventSelect模型是Windows Sockets提供的另外一个有用的异步I/O模型.该模型允许一个或多个套接字上接收以事件为基础的网络事件通 ...

随机推荐

  1. bat 获取命令执行后的多个返回值,并取最后一个

    最近在使用bat,遇到了这样的问题,获取adb shell cat命令之后的所有返回值,查了很长时间,才找到,现分享给大家. 举例如下: @for /f "tokens=*" %% ...

  2. python ratelimit使用

    1.https://pypi.org/project/ratelimit/

  3. git2--常用命令

    Git 命令详解及常用命令 Git作为常用的版本控制工具,多了解一些命令,将能省去很多时间,下面这张图是比较好的一张,贴出了看一下: 关于git,首先需要了解几个名词,如下: ? 1 2 3 4 Wo ...

  4. Matplotlib基本图形之饼状图

    Matplotlib基本图形之饼状图 饼状图特点: 饼状图显示一个数据系列中各项大小与各项总和的比例饼状图的数据点显示为整个饼状图的百分比 示例代码 import os import time imp ...

  5. 【编程工具】Sublime Text3的安装和常用插件推荐

    本人刚刚学习 HTML,曾经上网找过一些编写 HTML 的软件,但感觉都不太好,经过三挑四选下,最终我决定选择 Sublime Text3 这款软件来作为学习工具,上网找到了许多实用的插件,在这里给大 ...

  6. NYOJ 232 How to eat more Banana

    How to eat more Banana 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 A group of researchers are designing ...

  7. hdu2083

    开始忘排序了. #include <stdio.h> #include <math.h> #include <algorithm> using namespace ...

  8. 九度oj 题目1014:排名

    题目描述:     今天的上机考试虽然有实时的Ranklist,但上面的排名只是根据完成的题数排序,没有考虑每题的分值,所以并不是最后的排名.给定录取分数线,请你写程序找出最后通过分数线的考生,并将他 ...

  9. RHEL7网卡命名规则

    systemd 和 udev 引入了一种新的网络设备命名方式:一致网络设备命名(CONSISTENT NETWORK DEVICE NAMING).根据固件.拓扑.位置信息来设置固定名字,带来的好处是 ...

  10. Android从Fragment跳转到Activity

    代码改变世界 Android从Fragment跳转到Activity Intent intent = new Intent(getActivity(), LoginActivity.class); s ...