笔记7:vb.net的异步读写数据流(使用线程、委托)

 

           在理解异步读写前,了解一下线程和委托是必要的。


一、线程与委托


        1、为什么要用异步?

              无论是MemoryStream,BufferedStream,FileStream数据流,一旦的读写开始,应用程序就会处于停滞状况。

              直到数据读写完成,并返回。

              文件数据的读写基本上是一种非常消耗资源的过程,处理的数据量越大,I/O对系统性能的影响就越明显。

              

             为了避免长时间等待I/O操作使程序处理“瘫痪”状态,异步I/O就显得非常重要。


             异步的实现就是使用一个新的线程来完成,主线程的任务并不影响,这样大大提高了程序的效能。


        2、线程

              每个程序有一个主线程,如果一个循环处于主线程中,程序在较长的循环,将出现“不响应”的情况。


              线程在System.Threading中。线程创建可专用于一个功能块(方法、函数),

                                                                   线程的开始用Start方法

                                                                   线程的结束用Abort方法


            下面感受一下线程作用:


             窗体上添加两Button,两个TextBox,代码如下,点击Button1启动循环,接着点击Button2.   

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim i As Int32
        For i = 0 To 123451
            TextBox1.Text = i
        Next
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        TextBox2.Text = "终于出现奇迹"
    End Sub
End Class

           

            可以明显看到虽然点击了Button1,但TextBox1的内容并没有什么变化,同时,在点击Button2时,TextBox并没有内容显示。

           这是因为线程正被循环一直占用,暂时无法响应Button2,直到循环完成后,它才终于忙过来处理Button2.

           这会给用户造成“程序已经无响应、死了”的误会。





           下面改善上面的做法,新建一个线程来专门处理循环,这样就不影响主线程响应Button2:

Imports System.Threading
Public Class Form1
    Dim mythread As Thread

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        mythread = New Thread(AddressOf ShowNumber) '构造线程
        mythread.Name = "myShowNumber"
        mythread.Start() '启动线程
    End Sub

    Private Sub ShowNumber()
        Dim i As Int32
        For i = 0 To 123451
            TextBox1.Text = i
        Next

        mythread.Abort() '终止线程
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        TextBox2.Text = "终于出现奇迹"
    End Sub
End Class

          然而一点击,发现出错,提示:线程间操作无效: 从不是创建控件“TextBox1”的线程访问它。

         

         这是因为Textbox1是主线程中的,却在另一个新的线程中访问,这种是不安全的,相当于去别人房间使用电视机。

         怎么办?这里可以用委托,委托能够进别人房间的人去使用电视机。



         3、委托

               委托的思想,就是自己不能干或不想干的事,委托另一个有能力或有权限的人去干那件事。

            

               实际上,我们一直要用委托思想,比如基本类型的变量名。Dim  i  As  Integer

               i变量名就是相当于委托,实际上,一个变量代表的是指定内存地址中的值,如果不用变量名,就得实际上引用这个内存的地址。

               而我们就用“变量名”来干操作这个地址里的东西。


                除了变量名可以用委托一样,方法也可以用委托,这就是我们普通所说的委托。

                定义和使用大致与变量名的方式一样:

                (1)定义委托类型:  Private Delegate Sub   MyDelegate(byval  k  as int32)     '参数多种,多个)

                                                    这里类似定义变量的类型一样。

                 (2)定义要赋的具体“值”:  这里的具体值,不是值,而是一个具体的方法,方法的形式必须与上面定义保持一致。就象变量名是整形时,赋值也应该是整形,而不是String.

                                                        例如:Private  Sub   YourSelfMethod(byval   m  as int32)     '方法名自定,但形式与(1)保持一致。

                   (3)调用这个值: 也就是委托去办事。用Invoke方法:Control.Invoke(New  MyDelegate(AddressOf  YourSelfMethod),  intValue)

                                                       这一步就把(1),(2)使用上了。


                下面接着上面的例子,使用委托来调用Form1中的TextBox1.

Imports System.Threading
Public Class Form1
    Dim mythread As Thread
    Private Delegate Sub VoidShow(ByRef i As Int32) '定义要委托的类型

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        mythread = New Thread(AddressOf ShowNumber)
        mythread.Name = "myShowNumber"
        mythread.Start()
    End Sub

    Private Sub ShowNumber()
        Dim i As Int32
        For i = 0 To 123451
            'TextBox1.Text = i
            Me.Invoke(New VoidShow(AddressOf TureShowNumber), i) '用New构造委托,再用Invoke执行
        Next

        mythread.Abort()
    End Sub

    '新加入的被委托要做的事
    Private Sub TureShowNumber(ByRef i As Int32)
        TextBox1.Text = i
    End Sub


    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        TextBox2.Text = "终于出现奇迹"
    End Sub
End Class

            

            点击Buttton1,可以看到因为新线程的使用,TextBox1中的数字一直在变量。

            而且,同时点击Button2程序不会“死机”,很快地响应。



           注意的是:因为线程的中止使用的是强制中断Abort,所以即时窗体会显示:

             System.Threading.ThreadAbortException 类型的第一次机会异常在 mscorlib.dll中发生

             这个不影响使用。

             





二、异步读写


         异步I/O与同步I/O最大的不同在于: 同步I/O只有完成整个I/O操作后,程序才会进行下一步(所以这之前象死机一样)。

                                                                        异步I/O在操作读写操作的同时,程序可以继续下一步工作,不影响程序其它执行。

 

          简单地说,主线程和新线程各自执行,不相互影响。

          即流程如下:

         


         程序(主线程)在左边开始时,就建立了新线程进行异步读写。

        在异步开始时,就传入了一个回调参数,这个用于异步完成时,自动调用这个参数所指的过程。

        其中的IAsyncResult表示异步操作的状态。结束异步操作时需要这个参数。


        一般我们在I/O操作时都是同步,异步在FileStream构造时就必须指明文件采用的异步方法:

Public Sub New ( _
	path As String, _
	mode As FileMode, _
	access As FileAccess, _
	share As FileShare, _
	bufferSize As Integer, _  '缓冲大小
	useAsync As Boolean _    'True为异步
)


         下面看一下异步操作的例子:

                 1、委托:只是为了在线程中调用窗体中的控件TextBox1来显示状态。

                 2、线程:是异步I/O的必要过程

                 3、回调函数:这是异步完成后,自动来通知或告之,异步I/O已经完成了(否则,怎么知道异步的结束呢?)



Imports System.IO
Imports System.Threading
Public Class Form1
    Dim btArray(15) As Byte
    Dim fs As FileStream
    Dim myThread As Thread
    Dim blnProcess As Boolean  '进程是否使用标志

    Private Delegate Sub ShowMyMessage(ByVal str As String) '线程中无法调用窗体控件,用委托解决

    '启动写或读进程
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        TextBox1.Text = ""
        Try
            If RadioButton2.Checked = True Then '写选中
                myThread = New Thread(AddressOf WriteData)
                myThread.Name = "WriteBulkData"
                myThread.Start()
            Else
                myThread = New Thread(AddressOf ReadData)
                myThread.Name = "ReadBulkData"
                myThread.Start()
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

    Private Sub WriteData()
        Try
            fs = New FileStream("D:\11.txt", FileMode.Open, FileAccess.Write, FileShare.Write, 16, True)
            Dim myWCB As New AsyncCallback(AddressOf MyAsyncWriteCallBack)
            blnProcess = True
            fs.BeginWrite(btArray, 0, 12, myWCB, Nothing)
            ProcessMessage("Write")
            fs.Close()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

    Private Sub ReadData()
        Try
            fs = New FileStream("d:\11.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 16, True)
            Dim myRCB As New AsyncCallback(AddressOf MyAsyncReadCallBack)
            blnProcess = True
            fs.BeginRead(btArray, 0, 16, myRCB, Nothing)
            ProcessMessage("Read")
            fs.Close()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

    Private Sub MyAsyncWriteCallBack(ByVal myIar As IAsyncResult)
        Thread.Sleep(50)
        blnProcess = False
        fs.EndWrite(myIar)

        '委托显示信息
        Dim str As String = "  异步线程数据写入完成。"
        Me.Invoke(New ShowMyMessage(AddressOf ShowMessage), str)
    End Sub

    Private Sub MyAsyncReadCallBack(ByVal myIar As IAsyncResult)
        Thread.Sleep(50)
        blnProcess = False
        fs.EndRead(myIar)

        '委托显示信息
        Dim str As String = "  异步线程数据读取完成。"
        Me.Invoke(New ShowMyMessage(AddressOf ShowMessage), str)
    End Sub

    Private Sub ShowMessage(ByVal str As String)
        TextBox1.Text &= Now.ToString & str & vbCrLf
    End Sub


    Private Sub ProcessMessage(ByVal strRW As String)
        Dim strMessage As String = ""
        If strRW = "Read" Then
            strMessage = "  判断异步正在读取..."
        Else
            strMessage = "  判断异步正在写入..."
        End If

        Do While blnProcess = True
            Me.Invoke(New ShowMyMessage(AddressOf ShowMessage), strMessage)
        Loop
        Thread.Sleep(50)

        strMessage = "  判断读写已经完成。"
        Me.Invoke(New ShowMyMessage(AddressOf ShowMessage), strMessage)
    End Sub
End Class

             

            上面通过一个循环不断判断异步进行得怎么样(实际上是用的全局blnProcess来判断)

            因为是例子,数据量不大,所以在过程加加入Sleep来延迟异步还在进行中。

            为了减少显示的信息,把时间延时量减小到50毫秒。





  • 8
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
VB.NET是一种面向对象的编程语言,它是微软公司开发的一种基于.NET框架的编程语言。下面是一些VB.NET学习笔记的内容: 1. 基本语法:VB.NET的语法与其他编程语言类似,包括变量声明、条件语句、循环语句等。学习者需要掌握基本的语法规则和关键字。 2. 数据类型:VB.NET支持多种数据类型,包括整型、浮点型、字符型、布尔型等。学习者需要了解各种数据类型的特点和使用方法。 3. 控制结构:学习者需要掌握条件语句(如if语句、switch语句)和循环语句(如for循环、while循环)等控制结构,以实现程序的流程控制。 4. 函数和过程:VB.NET支持函数和过程的定义和调用。学习者需要了解函数和过程的区别,以及如何传递参数和返回值。 5. 面向对象编程:VB.NET是一种面向对象的编程语言,学习者需要了解类、对象、继承、多态等面向对象的概念和使用方法。 6. 异常处理:学习者需要了解如何使用try-catch语句来捕获和处理异常,以提高程序的健壮性。 7. 文件操作:学习者需要了解如何文件、创建和管理文件夹等文件操作的基本知识。 8. 数据库编程:VB.NET可以与数据库进行交互,学习者需要了解如何连接数据库、执行SQL语句、数据库等数据库编程的基本知识。 9. GUI编程:VB.NET提供了丰富的GUI组件和控件,学习者需要了解如何设计窗体、添加控件、处理事件等GUI编程的基本知识。 10. 调试和测试:学习者需要了解如何使用调试工具来调试程序,以及如何编和运行单元测试来验证程序的正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值