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

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

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

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

这是一个非常重要的问题,在这种情况下,唯一方案是无论如何都要避免阻塞UI纯种。这反过来意味着为了防止阻塞UI线程,每个与UI有关的API必须只被允许异步调用 。这是Windows操作系统重新升级API的关键原因 ,其几乎把每个方法替换为异步方式。但是应用程序使用多线程来达到此目的会影响性能吗?当然会。然而考虑到只有一个用户,那么这是划算的。如果应用程序可以使用电脑的所有能力从而变得更加高效,而且这种能力 只为运行程序的唯一用户服务,这是好事。

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

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

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

一、   异步使用文件

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

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 = ; 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, , 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, , 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();
Console.WriteLine("开始异步读取文件"); Task<long>[] readTasks = new Task<long>[];
for (int i = ; i < ; i++)
{ readTasks[i] = SumFileContent(string.Format("test{0}.txt",i + )); } long[] sums = await Task.WhenAll(readTasks);
Console.WriteLine("所有文件中的和值:{0}", sums.Sum()); Console.WriteLine("开始删除文件");
Task[] delTasks = new Task[];
for (int i = ; i < ; i++)
{ string filename = string.Format("test{0}.txt",i + );
delTasks[i] = SimulateAsynchronousDelete(filename); } await Task.WhenAll(delTasks);
Console.WriteLine("删除文件结束");
} static string CreateFileContent()
{
var sb = new StringBuilder();
for (int i = ; i < ; i++)
{
sb.AppendFormat("{0}", new Random(i).Next(, ));
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 = ;
while (sr.Peek() > -)
{
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。

然后并行地异步地从所有文件中读取数据,统计每个文件内容,然后求总和。

最后,删除所有文件。

多线程编程学习笔记——使用异步IO(一)的更多相关文章

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

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  2. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

  3. 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端

    接上文 多线程编程学习笔记——使用异步IO 二.   编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...

  4. 多线程编程学习笔记——async和await(一)

    接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...

  5. 多线程编程学习笔记——async和await(二)

    接上文 多线程编程学习笔记——async和await(一) 三.   对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...

  6. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  7. [Java123] JDBC and Multi-Threading 多线程编程学习笔记

    项目实际需求:DB交互使用多线程实现 多线程编程基础:1.5  :( (假设总分10) 计划一个半月从头学习梳理Java多线程编程基础以及Oracle数据库交互相关的多线程实现 学习如何通过代码去验证 ...

  8. Java多线程编程(学习笔记)

    一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...

  9. Python3 多线程编程 - 学习笔记

    线程 什么是线程 特点 线程与进程的关系 Python3中的多线程 全局解释器锁(GIL) GIL是啥? GIL对Python程序有啥影响? 改善GIL产生的问题 Python3关于多线程的模块 多线 ...

随机推荐

  1. Io 异常: The Network Adapter could not establish the connection

    新接触一个项目,导入源码,在本地启动的时候后台报了一个错误: Could not discover the dialect to use. java.sql.SQLException: Io 异常: ...

  2. 【原创】java NIO FileChannel 学习笔记 FileChannel 简介

    java NIO 中FileChannel 的实现类是  FileChannelImpl,FileChannel本身是一个抽象类. 先介绍FileChannel File Channels 是线程安全 ...

  3. 基于阿里云的JavaEE系统框架介绍

    基于阿里云的系统框架展望 1) CDN 用于缓存静态文件等等.七牛和阿里的都还可以. 七牛要做的久一点,各种图片处理的接口要完善一些 阿里的CDN要稍微好一点点,但是没有不安全的访问方式,访问稍微没有 ...

  4. java构造器执行顺序一个有趣的简单实例

    一 Animal为父类,构造器中调用public(default.protected) say方法,Dog继承了Animal,并重载了say方法.新建Dog对象,查看运行结果,若将Animal中say ...

  5. 5、员工上班时间的问题 - CEO之公司管理经验谈

    员工上班时间一般是根据公司的规章制度来制定的.当然,在不同的地点也有不同的做法.比如北京.上海.广州.深圳这些重点的大点的城市,加班的时间就相对比较多一些.但是按照笔者的想法,一般是一天7-8小时工作 ...

  6. Selectize使用总结

    一.简介 Selectize是一个可扩展的基于jQuery 的自定义下拉框的UI控件.它对展示标签.联系人列表.国家选择器等比较有用.它的大小在~ 7kb(gzip压缩)左右.提供一个可靠且体验良好的 ...

  7. 抽象方法为什么不能被private与static修饰

    private private访问修饰符修饰的方法只能在本类当中使用.所以,必然不能用private去修饰抽象方法.抽象方法一定是要被子类去重写的. static Java中用static修饰符修饰的 ...

  8. 【最大权闭合子图】bzoj4873 [Shoi2017]寿司餐厅

    4873: [Shoi2017]寿司餐厅 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 369  Solved: 256[Submit][Status ...

  9. for循环相关的一个问题

    首先,我在for循环外定义了两个变量. //在4条直线方向,获取预置点两端的8个点的棋盘信息 ,r=,c=;//step代表直线,r,c分别代表加上偏移量之后的坐标 ,myCount=,hisCoun ...

  10. 《SpringMVC从入门到放肆》一、概述

    一.SpringMVC概述 View Service Dao DB Spring MVC interface interface Mysql impls impls SpringMVC也叫Spring ...