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

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

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

假设以下场景,如果在客户端运行程序,最的事情之一是有一个响应的用户界面。这意味着无论应用程序发生什么,所有的用户界面元素都要保持 快速运行,用户能够从应用程序得到快速响应。达到这一点并不容易!如果你尝试在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. qrc资源文件加载后,裸机环境下图片不显示

    问题描述:在qt开发环境下,使用qss进行界面美化工作,里面包含许多图片资源.最后项目决定把这些图片资源和代码一起打包.然后就把图片资源和qss文件一起编入qrc文件中进行编译.在本机开发环境下是没有 ...

  2. raspberrypi 3代B 配置摄像头

    raspberrypi 3代B 配置摄像头 硬件环境: 树莓派3B (element 14版) 树莓派3夜视摄像头800万像素(element 14版) 金士顿 64GB TF Class 10 UH ...

  3. MySQL主从复制原理以及架构

    1 复制概述 Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的 数据复制到其它主机(slaves)上,并 ...

  4. [编织消息框架][消息服务]rmi

    RMI(即Remote Method Invoke 远程方法调用) 远程对象: 用于远程客户端调用 必需继承java.rmi.Remote,每个调用方法必须添加java.rmi.RemoteExcep ...

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

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

  6. js写基础insertAfter()方法

    //DOM没有提供insertAfter()方法 function insertAfter(newElement, targetElement){ var parent = targetElement ...

  7. python的range()函数

    range函数的三种用法:>>> range(1,5) # 代表从1到5(不包含5) [1, 2, 3, 4] >>> range(1,5,2) # 代表从1到5, ...

  8. robotframework的学习笔记(十六)----robotframework标准库String

    官方文档:http://robotframework.org/robotframework/latest/libraries/String.html Introduction A test libra ...

  9. HDFS High Availability Using the Quorum Journal Manager

    http://hadoop.apache.org/docs/r2.9.0/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.htm ...

  10. Factom(公证通)--基于区块链的存证系统

    Factom这个Solution在2014年的时候就已经推出了,现在已经2018年了,我才来写这一篇分析文章可能有些迟了,但是它是十分具有参考价值的.因为现阶段来开区块链虽然炒得火热--养猫.养狗.草 ...