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

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

一、线程与委托

?1、为什么要用异步?

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

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

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

 

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

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

?2、线程

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

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

线程的开始用Start方法

线程的结束用Abort方法

下面感受一下线程作用:

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

  1. Public?Class?Form1
  2. ????Private?Sub?Button1_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button1.Click
  3. ????????Dim?i?As?Int32
  4. ????????For?i?=?0?To?123451
  5. ????????????TextBox1.Text?=?i
  6. ????????Next
  7. ????End?Sub
  8. ????Private?Sub?Button2_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button2.Click
  9. ????????TextBox2.Text?=?"终于出现奇迹"
  10. ????End?Sub
  11. End?Class

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

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

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

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

  1. Imports?System.Threading
  2. Public?Class?Form1
  3. ????Dim?mythread?As?Thread
  4. ????Private?Sub?Button1_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button1.Click
  5. ????????mythread?=?New?Thread(AddressOf?ShowNumber)?'构造线程
  6. ????????mythread.Name?=?"myShowNumber"
  7. ????????mythread.Start()?'启动线程
  8. ????End?Sub
  9. ????Private?Sub?ShowNumber()
  10. ????????Dim?i?As?Int32
  11. ????????For?i?=?0?To?123451
  12. ????????????TextBox1.Text?=?i
  13. ????????Next
  14. ????????mythread.Abort()?'终止线程
  15. ????End?Sub
  16. ????Private?Sub?Button2_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button2.Click
  17. ????????TextBox2.Text?=?"终于出现奇迹"
  18. ????End?Sub
  19. 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.

  1. Imports?System.Threading
  2. Public?Class?Form1
  3. ????Dim?mythread?As?Thread
  4. ????Private?Delegate?Sub?VoidShow(ByRef?i?As?Int32)?'定义要委托的类型
  5. ????Private?Sub?Button1_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button1.Click
  6. ????????mythread?=?New?Thread(AddressOf?ShowNumber)
  7. ????????mythread.Name?=?"myShowNumber"
  8. ????????mythread.Start()
  9. ????End?Sub
  10. ????Private?Sub?ShowNumber()
  11. ????????Dim?i?As?Int32
  12. ????????For?i?=?0?To?123451
  13. ????????????'TextBox1.Text?=?i
  14. ????????????Me.Invoke(New?VoidShow(AddressOf?TureShowNumber),?i)?'用New构造委托,再用Invoke执行
  15. ????????Next
  16. ????????mythread.Abort()
  17. ????End?Sub
  18. ????'新加入的被委托要做的事
  19. ????Private?Sub?TureShowNumber(ByRef?i?As?Int32)
  20. ????????TextBox1.Text?=?i
  21. ????End?Sub
  22. ????Private?Sub?Button2_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button2.Click
  23. ????????TextBox2.Text?=?"终于出现奇迹"
  24. ????End?Sub
  25. 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构造时就必须指明文件采用的异步方法:

  1. Public?Sub?New?(?_
  2. ????path?As?String,?_
  3. ????mode?As?FileMode,?_
  4. ????access?As?FileAccess,?_
  5. ????share?As?FileShare,?_
  6. ????bufferSize?As?Integer,?_??'缓冲大小
  7. ????useAsync?As?Boolean?_????'True为异步
  8. )

 

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

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

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

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

 

  1. Imports?System.IO
  2. Imports?System.Threading
  3. Public?Class?Form1
  4. ????Dim?btArray(15)?As?Byte
  5. ????Dim?fs?As?FileStream
  6. ????Dim?myThread?As?Thread
  7. ????Dim?blnProcess?As?Boolean??'进程是否使用标志
  8. ????Private?Delegate?Sub?ShowMyMessage(ByVal?str?As?String)?'线程中无法调用窗体控件,用委托解决
  9. ????'启动写或读进程
  10. ????Private?Sub?Button1_Click(sender?As?Object,?e?As?EventArgs)?Handles?Button1.Click
  11. ????????TextBox1.Text?=?""
  12. ????????Try
  13. ????????????If?RadioButton2.Checked?=?True?Then?'写选中
  14. ????????????????myThread?=?New?Thread(AddressOf?WriteData)
  15. ????????????????myThread.Name?=?"WriteBulkData"
  16. ????????????????myThread.Start()
  17. ????????????Else
  18. ????????????????myThread?=?New?Thread(AddressOf?ReadData)
  19. ????????????????myThread.Name?=?"ReadBulkData"
  20. ????????????????myThread.Start()
  21. ????????????End?If
  22. ????????Catch?ex?As?Exception
  23. ????????????MessageBox.Show(ex.Message)
  24. ????????End?Try
  25. ????End?Sub
  26. ????Private?Sub?WriteData()
  27. ????????Try
  28. ????????????fs?=?New?FileStream("D:\11.txt",?FileMode.Open,?FileAccess.Write,?FileShare.Write,?16,?True)
  29. ????????????Dim?myWCB?As?New?AsyncCallback(AddressOf?MyAsyncWriteCallBack)
  30. ????????????blnProcess?=?True
  31. ????????????fs.BeginWrite(btArray,?0,?12,?myWCB,?Nothing)
  32. ????????????ProcessMessage("Write")
  33. ????????????fs.Close()
  34. ????????Catch?ex?As?Exception
  35. ????????????MessageBox.Show(ex.Message)
  36. ????????End?Try
  37. ????End?Sub
  38. ????Private?Sub?ReadData()
  39. ????????Try
  40. ????????????fs?=?New?FileStream("d:\11.txt",?FileMode.Open,?FileAccess.Read,?FileShare.Read,?16,?True)
  41. ????????????Dim?myRCB?As?New?AsyncCallback(AddressOf?MyAsyncReadCallBack)
  42. ????????????blnProcess?=?True
  43. ????????????fs.BeginRead(btArray,?0,?16,?myRCB,?Nothing)
  44. ????????????ProcessMessage("Read")
  45. ????????????fs.Close()
  46. ????????Catch?ex?As?Exception
  47. ????????????MessageBox.Show(ex.Message)
  48. ????????End?Try
  49. ????End?Sub
  50. ????Private?Sub?MyAsyncWriteCallBack(ByVal?myIar?As?IAsyncResult)
  51. ????????Thread.Sleep(50)
  52. ????????blnProcess?=?False
  53. ????????fs.EndWrite(myIar)
  54. ????????'委托显示信息
  55. ????????Dim?str?As?String?=?"??异步线程数据写入完成。"
  56. ????????Me.Invoke(New?ShowMyMessage(AddressOf?ShowMessage),?str)
  57. ????End?Sub
  58. ????Private?Sub?MyAsyncReadCallBack(ByVal?myIar?As?IAsyncResult)
  59. ????????Thread.Sleep(50)
  60. ????????blnProcess?=?False
  61. ????????fs.EndRead(myIar)
  62. ????????'委托显示信息
  63. ????????Dim?str?As?String?=?"??异步线程数据读取完成。"
  64. ????????Me.Invoke(New?ShowMyMessage(AddressOf?ShowMessage),?str)
  65. ????End?Sub
  66. ????Private?Sub?ShowMessage(ByVal?str?As?String)
  67. ????????TextBox1.Text?&=?Now.ToString?&?str?&?vbCrLf
  68. ????End?Sub
  69. ????Private?Sub?ProcessMessage(ByVal?strRW?As?String)
  70. ????????Dim?strMessage?As?String?=?""
  71. ????????If?strRW?=?"Read"?Then
  72. ????????????strMessage?=?"??判断异步正在读取..."
  73. ????????Else
  74. ????????????strMessage?=?"??判断异步正在写入..."
  75. ????????End?If
  76. ????????Do?While?blnProcess?=?True
  77. ????????????Me.Invoke(New?ShowMyMessage(AddressOf?ShowMessage),?strMessage)
  78. ????????Loop
  79. ????????Thread.Sleep(50)
  80. ????????strMessage?=?"??判断读写已经完成。"
  81. ????????Me.Invoke(New?ShowMyMessage(AddressOf?ShowMessage),?strMessage)
  82. ????End?Sub
  83. End?Class

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

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

为了减少显示的信息,把时间延时量减小到50毫秒。转载请注明出处:

转载自http://lxfamn.cn/blog

未经允许不得转载:lxfamn » vb.net的异步线程、委托 读写数据流(使用线程、委托)

赞 (0) 打赏

置顶推荐

评论 0

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏