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

前端之家收集整理的这篇文章主要介绍了笔记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,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",FileAccess.Read,FileShare.Read,True)
            Dim myRCB As New AsyncCallback(AddressOf MyAsyncReadCallBack)
            blnProcess = True
            fs.BeginRead(btArray,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毫秒。

猜你在找的VB相关文章