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

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

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

假设以下场景,如果在客户端运行程序,最的事情之一是有一个响应的用户界面。这意味着无论应用程序发生什么,所有的用户界面元素都要保持 快速运行,用户能够从应用程序得到快速响应。达到这一点并不容易!如果你尝试在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. VS环境下C++如何检查是否内存泄漏

    c++如何检查是否内存泄漏 今天在做OpenGL引擎的时候,突然想到检查一下内存泄漏.具体是我做了一个渲染类Render,将所有世界中存在的物体的指针都存放在这个类中.于是我不免担心,在Render中 ...

  2. Java:编码与乱码问题

    一.为什么要编码? 由于人类的语言太多,因而表示这些语言的符号太多,无法用计算机的一个基本的存储单元----byte来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解. byte一个字节即8 ...

  3. 工作我们是专业的之css规范

    我一直认为专业是一种态度.不同于业余,专业代表无论技术高低都会遵守一定的规范,专业代表对某一领域不断的精益求精.专业就是比业余逼格高. 习惯书写规范 css 属性声明的顺序:Positioning(定 ...

  4. easyui属性赋值

    了解easyui tree组件的童鞋估计都知道tree的node有他自己单独的属性(id,text,iconCls,checked,state,attribute,target).而原先这个几个属性想 ...

  5. 添加sqljdbc的maven依赖JAVA环境配置

    sqljdbc是微软sql server的jdbc驱动 使用sqljdbc需要从微软的官方网站下载jar包: http://www.microsoft.com/en-us/download/detai ...

  6. php类自动加载

    __autoload 新建一个index.php <?php $d = new z(); function __autoload($class) //自动捕获new的类名 { $file = $ ...

  7. eclipse中设置python的版本

    (mac系统)由于系统的python是内置的,无法直接查找到安装文件,则可在eclipse偏好设置-PyDev - Interpreters-Python Interpreter其右边选择Quick ...

  8. 老罗最新发布了“子弹短信”这款IM,主打熟人社交能否对标微信?

    1.引言 2018年8月20日,锤子科技在北京召开了夏季新品发布会.除了新手机,发布会上还正式推出了主打语音功能的即时通讯IM聊天工具:子弹短信.这款工具此前今年早些时候在「鸟巢」发布会上初次亮相,在 ...

  9. Javascript高级编程学习笔记(64)—— 事件(8)键盘与文本事件

    键盘与文本事件 用户在使用键盘时会触发键盘事件 “DOM2级事件”最初规定了键盘事件,但是最后在定稿时又删除了相应内容 所以键盘事件被放入了DOM3级事件的规范中 总的来说有三个键盘事件: keydo ...

  10. Javascript高级编程学习笔记(59)—— 事件(3)事件对象

    事件对象 在触发DOM‘事件时,会产生一个事件对象 event 该对象包含着所有与事件有关的信息 所有浏览器都支持 event 对象但是支持的方式有所不同 DOM事件对象 兼容DOM的浏览器会将eve ...