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

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

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

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

    JavaScript 中,万物皆对象!(对于编程而言,可以说万物皆对象.) js中的原型链的作用时什么呢? 我自己的理解是,给一个人赋予一些技能, function people(name,age,s ...

  2. HTML5调用手机的Datepicker(日期选择器)

    HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证,包含了如下新的输入类型: email url number range Date pickers (date, month, ...

  3. MySQL远程连接失败(错误码:2003)

    一 环境信息 服务器系统:Ubuntu 18.04 服务器MySQL版本:14.14 Distrib 5.7.25 本地系统:Kali Linux 本地客户端:python3交互模式 本地开发环境:p ...

  4. For语句的衍生对象

    for in语句: for...in 语句用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作). for...in 语句用于对数组或者对象的属性进行循环操作. for ... in 循环中的 ...

  5. Notes : <Hands-on ML with Sklearn & TF> Chapter 6

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  6. [solution]JZOJ-5838 旅游路线

    [solution] JZOJ-5838 旅游路线 Time Limits 1000ms,Memory Limits 128MB 题面 Description GZOI队员们到X镇游玩.X镇是一个很特 ...

  7. Mac 下 python 环境问题

    一.Mac下,可能存在的 python 环境: 1.Mac系统自带的python环境在(由于不同的 mac 系统,默认自带的 python 版本可能不一样): Python 2.7.10: /Syst ...

  8. android-音量管理

    推荐简书夕月风: 前两个主要设计音频建设置流程. 一.https://www.jianshu.com/p/a48fc2c830da 二.https://www.jianshu.com/p/892761 ...

  9. 安装memcache遇到的坑

    memcached 在make的时候出错,解决办法: # vim memcached.c 修改如下几行56 /* FreeBSD 4.x doesn't have IOV_MAX exposed. * ...

  10. sflow介绍与安装过程

    介绍: sFlow技术是一种以设备端口为基本单元的数据流随机采样的流量监控技术,不仅可以提供完整的第二层到第四层甚至全网范围内的实时流量信息,而且可以适应超大网络流量(如大于10Gbit/s)环境下的 ...