C# 并行编程 之 异步编程模型

概要

由一个应用场景引发的思考:程序要处理一个密集的I/O工作,在数据到达之前,程序要挂起等待。通常此时会专门启动一个I/O线程来进行处理。线程本身比较耗费资源,启动一个线程后,如果它要处理异步的任务,在没有数据时线程处于阻塞状态,这样是对系统资源的浪费,如果I/O的线程还不止一个,那浪费的资源就更多了。

这时,可以考虑使用Task.Factory.FromAsync,而不是直接使用线程。使用Task.Factory.FromAsync可以将任务调度,线程阻塞等工作交给CLR线程池引擎,由任务调度器调度,这样对于系统的使用会更加的高效。

– 异步编程模型(Asynchronous Programming Model APM)
.Net Framework 1 已经引入了这个模式,也称Begin/End 模式。一个 以Begin为前缀 的方法加载异步执行,并返回一个System.IAsyncResult对象,这个对象表示这个异步操作的状态。Begin方法可以接受一些与异步操作相关的参数,和一个System.AsyncCallback对象。这个对象表示异步操作结束时要调用的方法。然后可以调用以End为前缀的方法,以End为前缀的方法会阻塞当前任务或线程,直到I/O线程完成。它还可以返回操作结果相关的信息。

– 基于事件的异步编程模式(Event-Based Asynchronous Pattern EAP)
.Net Framework 2 为异步操作引入了这个模式。一个以Async为后缀的方法加载异步执行,当异步执行完成或取消时,异步操作会抛出一个事件,一个委托可以与这个事件绑定,并提供处理事件的回调函数。


示例程序:读入多个文件,并将文件内容合并到一起。

using System;
using System.Collections.Generic;
using System.Text;

using System.IO;
using System.Threading.Tasks;

namespace Sample9_1_apm_basic
{
    class Program
    {
        private static string[] files = { "file01.txt", "file02.txt", "file03.txt", "file04.txt", "file05.txt", "file06.txt"};
        private const int BUFFER_SIZE = 0x2000;

        private static Task<string> ReadAllTextAsync(string strPath)
        {
            FileInfo info = new FileInfo(strPath);
            if (!info.Exists)
            {
                throw new FileNotFoundException();
            }

            byte[] data = new byte[info.Length];

            FileStream stream = new FileStream(strPath, FileMode.Open, FileAccess.Read, FileShare.Read, BUFFER_SIZE, true);

            Task<int> task = Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, data, 
                                                         0, data.Length, null, TaskCreationOptions.None);

            return task.ContinueWith((t) => 
            {
                stream.Close();
                Console.WriteLine("Task Read file " + strPath + ":" + data.Length + " bytes");

                return (data.Length > 0) ? new UTF8Encoding().GetString(data) : "";

            }, TaskContinuationOptions.ExecuteSynchronously);

        }

        static void Main(string[] args)
        {
            List<Task<string>>fileTasks = new List<Task<string>>(files.Length);

            foreach (string fileName in files)
            {
                var readTask = ReadAllTextAsync(fileName);
                fileTasks.Add(readTask);
            }

            Task.WaitAll(fileTasks.ToArray());

            foreach (Task<string> fileTask in fileTasks)
            {
                Console.WriteLine(fileTask.Result);
            }

            Console.ReadLine();
        }
    }
}

函数接口说明

这里主要用到的接口有三个:

Task.Factory.FromAsync()
对于它来说最重要的就是Begin和End函数了,但除了Begin和End 之外它还要一大串参数。这些参数就要看stream.BeginRead了。
https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.fromasync(v=vs.110).aspx

stream.BeginRead
接口定义:
public virtual IAsyncResult BeginRead(
byte[] buffer, int offset, int count,
AsyncCallback callback, Object state)

与程序中的接口对照一下,FromAsync()中除了Begin和End外,其他的参数基本全是给BeginRead用的。
https://msdn.microsoft.com/en-us/library/dd321290(v=vs.110).aspx

stream.EndRead:这个简单些,主要是对于返回值的。
https://msdn.microsoft.com/en-us/library/system.io.stream.endread(v=vs.110).aspx

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值