多线程编程学习笔记——使用异步IO

接上文 多线程编程学习笔记——使用并发集合(一)html

接上文 多线程编程学习笔记——使用并发集合(二)编程

接上文 多线程编程学习笔记——使用并发集合(三)服务器

 

         假设如下场景,若是在客户端运行程序,最的事情之一是有一个响应的用户界面。这意味着不管应用程序发生什么,全部的用户界面元素都要保持 快速运行,用户可以从应用程序获得快速响应。达到这一点并不容易!若是你尝试在Windows系统中打开记事本并加载一个有几兆大小的文档,应用程序窗口将交结一段的时间,由于整个文件要先从硬盘中加载,而后程序才能开始处理用户输入。网络

        这是一个很是重要的问题,在这种状况下,惟一方案是不管如何都要避免阻塞UI纯种。这反过来意味着为了防止阻塞UI线程,每一个与UI有关的API必须只被容许异步调用 。这是Windows操做系统从新升级API的关键缘由 ,其几乎把每一个方法替换为异步方式。可是应用程序使用多线程来达到此目的会影响性能吗?固然会。然而考虑到只有一个用户,那么这是划算的。若是应用程序可使用电脑的全部能力从而变得更加高效,并且这种能力 只为运行程序的惟一用户服务,这是好事。多线程

         接下来看看第二种状况。若是程序运行在服务器端,则是彻底不一样的情形。可伸缩性是最高优先级,这意味着单个 用户消耗越少的资源越好。若是为每一个用户建立多个线程,则可伸缩性并很差。以高效的方式来平衡应用程序资源的消耗是个很是复杂的问题。例如,在ASP.NET中,咱们使用工做线程池来服务客户端请求。这个池的工做线程是有限的,因此不得不最小化每一个工做线程的使用时间以便达到高伸缩性。这意味着须要把工做线程越快越好地放回到池中,从而能够服务下一个请求。若是咱们启动了一个须要计算的异步操做,则整个工做流程会很低效。首先从线程池中取出一个工做 线程用以服务客户端请求。而后取出另外一个工做线程并开始处理异步操做。如今有两个工做线程都在处理请求,若是第一个线程能作些有用的事则很是好。惋惜,一般状况下,咱们简单等待异步 操做完成,可是咱们却消费了两个工做 线程,而不是一个。在这个场景中,异步 比同步执行实际上更糟糕!咱们不须要使用全部CPU核心,由于咱们已经在服务不少客户端,它们已经使用了CPU的全部计算能力。咱们无须保持第一个线程响应,由于这没有用户界面。那么为何咱们应该在服务端使用异步呢?并发

        答案是只有异步输入/输出操做才应用使用异步。目前,现代计算机经过有一个磁盘驱动器来存储文件,一块网卡来经过网络发送与接收数据。全部这些设备都有本身的芯片,以很是底层的方式来管理输入/输出操做并发信号 给操做系统。这种执行I/O任务的方式被称为I/O线程。dom

          在ASP.NET中,一旦有一个异步的I/O操做在工做线程开始时,它会被当即返回到线程池中。当这个操做继续运行时,这个线程能够服务其余的客户端。最终,当操做发出信号完成时,ASP.NET基础设施从线程池中获取一个空闲的工做线程,而后会完成这个操做。异步

1、   异步使用文件async

      本救命学习如何使用异步的方式读写一个文件。异步编程

 1.示例代码以下。

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ThreadIODemo
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("--开始 使用 异步 I/O 线程 -- ");
            var t = ReadWriteAsyncIO();
            t.GetAwaiter().GetResult();
            Console.Read();
        }

        const int BUFFER_SIZE = 4096;

        async static Task ReadWriteAsyncIO()
        {

            using (var fs = new FileStream("test1.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None, BUFFER_SIZE))
            {

                Console.WriteLine("1. 使用 I/O 线程 是否异步:{0}",fs.IsAsync);
                byte[] buffer = Encoding.UTF8.GetBytes(CreateFileContent());

                var writeTask = Task.Factory.FromAsync(fs.BeginWrite, fs.EndWrite, buffer, 0, buffer.Length, null);
                await writeTask;

            }

            using (var fs = new FileStream("test2.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None,
BUFFER_SIZE, FileOptions.Asynchronous)) { Console.WriteLine(
"2. 使用 I/O 线程 是否异步:{0}",fs.IsAsync); byte[] buffer = Encoding.UTF8.GetBytes(CreateFileContent()); var writeTask = Task.Factory.FromAsync(fs.BeginWrite, fs.EndWrite, buffer, 0, buffer.Length, null); await writeTask; } using (var fs = File.Create("test3.txt", BUFFER_SIZE, FileOptions.Asynchronous)) { using (var sw = new StreamWriter(fs)) { Console.WriteLine("3. 使用 I/O 线程 是否异步:{0}",fs.IsAsync); await sw.WriteAsync(CreateFileContent()); } } using (var sw = new StreamWriter("test4.txt", true)) { Console.WriteLine("4. 使用 I/O 线程 是否异步:{0}",((FileStream)sw.BaseStream).IsAsync); await sw.WriteAsync(CreateFileContent()); } System.Threading.Thread.Sleep(1000); Console.WriteLine("开始异步读取文件"); Task<long>[] readTasks = new Task<long>[4]; for (int i = 0; i < 4; i++) { readTasks[i] = SumFileContent(string.Format("test{0}.txt",i + 1)); } long[] sums = await Task.WhenAll(readTasks); Console.WriteLine("全部文件中的和值:{0}", sums.Sum()); Console.WriteLine("开始删除文件"); Task[] delTasks = new Task[4]; for (int i = 0; i < 4; i++) { string filename = string.Format("test{0}.txt",i + 1); delTasks[i] = SimulateAsynchronousDelete(filename); } await Task.WhenAll(delTasks); Console.WriteLine("删除文件结束"); } static string CreateFileContent() { var sb = new StringBuilder(); for (int i = 0; i < 100000; i++) { sb.AppendFormat("{0}", new Random(i).Next(0, 99999)); sb.AppendLine(); } return sb.ToString(); } async static Task<long> SumFileContent(string filename) { using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, BUFFER_SIZE, FileOptions.Asynchronous)) using (var sr = new StreamReader(fs)) { long sum = 0; while (sr.Peek() > -1) { string line = await sr.ReadLineAsync(); sum += long.Parse(line); } return sum; } } static Task SimulateAsynchronousDelete(string filename) { return Task.Run(() => File.Delete(filename)); } } }

 

2.程序运行结果,以下图。

 

      当程序运行时,咱们以不一样的方式建立了4个文件,并写入一些随机数据。

      在第一个例子中,使用的是FileStream类以及其方式,将异步编程模式API转换成任务。

      在第二个例子中,使用的是FileStream类以及其方式,不过在构造的时候提供了FileStream.Asynchronous参数 。

      在第三个例子使用了一些简化的API,好比File.Create方法和StreamWrite类。它也使用I/O线程,咱们可使用Stream.iSaSYNC属性来检查。

     在第四个例子说明了过度简化 也很差。这里咱们借助异步委托调用来模拟异步I/O,其实并无使用异步I/O。

      而后并行地异步地从全部文件中读取数据,统计每一个文件内容,而后求总和。

        最后,删除全部文件。

相关文章
相关标签/搜索