vb.net 多线程 访问界面控件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vb.net 多线程 访问界面控件相关的知识,希望对你有一定的参考价值。
网上查了,都说用委托 invoke,就是不知道具体怎么做。麻烦大神了!
要执行的函数是 daochu() 就是把 datagridview1导出excel
private sub daochu()
SaveFileDialog1.DefaultExt = "xls"
SaveFileDialog1.Filter = "Text documents *.xls|*.xls|Text documents *.xlsx|*.xlsx|All File *.*|*.*"
Dim yon As SaveOptions = SaveFileDialog1.ShowDialog()
If yon = 1 Then
ToolStripProgressBar1.Style = ProgressBarStyle.Blocks
(省略创建exce 对象)
With xlapp.ActiveSheet
.cells(1, 1).value = Label1.Text & " 汇率 " & TextBox1.Text
.range("A1:M1").MergeCells = True
.Range("A1").HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter
.Range("A1").VerticalAlignment = Excel.XlVAlign.xlVAlignCenter
' .range("A1:N1").Borders(XlBordersIndex.xlEdgeBottom).LineStyle = Excel.XlLineStyle.xlLineStyleNone
.range("A1:X1").Borders(Excel.XlBordersIndex.xlEdgeBottom).LineStyle = 1
.range("A2:X2").Borders(Excel.XlBordersIndex.xlEdgeBottom).LineStyle = 1
'.range("A20:N20").Borders(Excel.XlBordersIndex.xlEdgeBottom).LineStyle = 1
.cells(2, 1).value = "编号"
For i = 0 To Datagridview1.RowCount - 1
For j = 0 To Datagridview1.ColumnCount - 1
.cells(3 + i, j + 1).value = Datagridview1.Rows(i).Cells(j).Value
.cells(3 + i, j + 1).Borders(Excel.XlBordersIndex.xlEdgeTop).LineStyle = 1
.cells(3 + i, j + 1).Borders(Excel.XlBordersIndex.xlEdgeBottom).LineStyle = 1
.cells(3 + i, j + 1).Borders(Excel.XlBordersIndex.xlEdgeRight).LineStyle = 1
.cells(3 + i, j + 1).Borders(Excel.XlBordersIndex.xlEdgeLeft).LineStyle = 1
If CStr(.cells(3 + i, 2).value) = "合计" Then .range("A" & 3 + i & ":X" & 3 + i).Interior.Color = 10079487
p_value = (i * (Datagridview1.ColumnCount) + j + 1) / (Datagridview1.RowCount * Datagridview1.ColumnCount)
If p_value <= 100 Then
ToolStripProgressBar1.Value = p_value
End If
Application.DoEvents()
Next
Next
End With
省略保存excel代码
end sub
sub button1_click ()
Dim Thread2 As New System.Threading.Thread(AddressOf daochu)
Thread2.ApartmentState = ApartmentState.STA
Thread2.Start()
end sub
这个地方用线程,然后再用invoke简直是多此一举追问
这是导出 excel,数据很多,开始导出后,好几分钟,软件不能动。所以我想用多线程,这样用户可以继续其他操作。
追答不需要委托,我不知道到你的数据量有多大,不过我觉得做法是
显示savedialogue显示保存位置
datagridview的数据集生成一份拷贝
3. 遍历拷贝的数据集,生成excel
其中第三步封装为方法,放在线程中执行
追问我把 datagridview 改成 datatble 了,数据从数据库来 ,我真笨!
另外一个小问题,代码都没变,就是那个ToolStripProgressBar1.Value = p_value这个怎么办?我要再一边遍历数据时一边显示进度条
这一步要使用委托,
其实如果你代码规范不严格的话,直接在窗体启动的时候设置CheckForIllegalCrossThreadCalls = false; 就行了
这个没用。我在load里写了这句。有说什么的控件不能成为什么控件的父级。。。
悲剧啊。现在我只好定义一个全局变量,用 timer来不断更新那个进度条
VB.NET多线程入门
最近项目中遇到了一个处理速度慢堵塞用户界面操作的问题,因此想用多线程来解决。
在处理数据的循环中,新建线程,在新建的线程中处理数据。多线程同时处理数据,以此来达到加速的目的,使用户界面操作变得流畅。
在多任务操作系统中,我们可以在操作系统的协调下同时进行多个任务。各个任务以分时复用的形式来进行工作。Windows操作系统通过进程ID来管理各进程,每个进程至少包含一个线程,线程是进程中可以独立运行的程序片段。在主程序运行时,主程序可以启动线程,线程与主程序同时运行。线程是系统中分时处理的最小单位,也就是说线程可以与主程序并行运行,参与同分时处理。线程有自己独立的栈处理数据,它在与主程序同时运行时可以共享主程序定义的变量、函数。只有当线程运行结束才把控制权还给主程序。
创建线程最直接的方法是创建新的线程类实例,并使用Address Of语句为运行的过程传递委托。但是这种方法不能传递参数和返回值。
我们可以通过将在单独的线程中运行的过程包装到类或结构中,为它们提供参数,并使之能返回参数。
下面是一个新建线程的小demo:
Class TasksClass
Public StrArg As String
Public RetVal As Boolean
Public resultFlag As Boolean
Public Event ResultEvent(ByVal resultFlag As Boolean)
Public Sub SomeTask()
' 将 StrArg 字段用作参数。
MessageBox.show("StrArg 包含字符串" & StrArg)
RetVal = True ' 设置返回参数的返回值。
End Sub
End Class
Public Class Test
Private Sub Test_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DoWork()
End Sub
' 要使用类,请设置存储参数的属性或字段,
' 然后,根据需要异步调用方法。
Sub DoWork()
Dim Tasks As New TasksClass()
Dim Thread1 As New System.Threading.Thread(AddressOf Tasks.SomeTask)
Tasks.StrArg = "参数A" ' 设置用作参数的字段。
Thread1.Start() ' 启动新线程。
Thread1.Join() ' 等待线程 1 运行结束。
' 显示返回值。
MessageBox.show("线程 1 返回值" & Tasks.RetVal)
End Sub
End Class
这样一个线程就被新建出来了。
但是事实上,创建过多的线程反而会影响性能,因为各个线程之间是分时复用的,操作系统需要在它们之间不断的切换,线程过多的时候,大量的时间消耗在线程切换上。
所以需要控制线程的数量。
假设我们只新建10个线程,剩余的数据等待这10个线程中的某个结束,再继续新建线程处理数据。使线程的总数一直保持在10个。
Public Class ThreadingObj
Public paper As WorkSpace
Public Sub ThreadingInsertPaper()
'多线程处理数据
End Sub
End Class
Private PaperList As List(Of WorkSpace) = New List(Of WorkSpace)
Dim ThreadingList As List(Of System.Threading.Thread) = New List(Of System.Threading.Thread)
For Each paper In PaperList '多线程处理PaperList If ThreadingList.Count < 10 Then '不到10个线程则继续新起线程 Dim ThreadingObject As New ThreadingObj Dim ThreadingTask_1 As New System.Threading.Thread(AddressOf ThreadingObject.ThreadingInsertPaper) ThreadingObject.paper = paper ThreadingList.Add(ThreadingTask_1) ThreadingTask_1.Start() ' 启动新线程。 Else Dim goOnFlag As Boolean = False '循环等待有线程结束 Do If CheckThreadingStatus() Then '存在已完成的线程 If ThreadingList.Count <= 10 Then Dim ThreadingObject As New ThreadingObj Dim ThreadingTask_1 As New System.Threading.Thread(AddressOf ThreadingObject.ThreadingInsertPaper) ThreadingObject.paper = paper ThreadingList.Add(ThreadingTask_1) ThreadingTask_1.Start() ' 启动新线程。 goOnFlag = True End If Else '所有线程都在进行中 End If Loop Until goOnFlag = True End If Next
Function CheckThreadingStatus() As Boolean
'返回True表示存在已完成的线程
If ThreadingList.Count <= 10 Then
For Each ThreadingTaskItem In ThreadingList
'ThreadingTaskItem.IsAlive
If ThreadingTaskItem.IsAlive = False Then
ThreadingTaskItem.Abort()
ThreadingList.Remove(ThreadingTaskItem)
Return True
End If
Next
End If
Threading.Thread.Sleep(100)
If ThreadingList.Count <= 10 Then
For Each ThreadingTaskItem In ThreadingList
If ThreadingTaskItem.IsAlive = False Then
Return True
End If
Next
End If
Return False
End Function
假设操作系统中有50个活跃的线程,如果我们的程序只有一个线程,那么程序就占用了系统资源的五十分之一。如果此时再多开一个线程,那么就占用了系统资源的2/51。我们的程序占用的资源越多,处理速度也就会更快一些。
因为各个线程之间是分时复用的,所以活跃的线程数量也会影响程序的效率。
有一种说法是2N + 2个线程数,是最有效率的。N是CPU的核数。但是这一说法也一直存在争议。
我的测试结果如下(我的电脑是i7 4770 ,四核八线程):
线程数 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 |
耗时 | 753 | 409 | 345 | 316 | 305 | 286 | 280 | 282 | 273 | 273 | 264 | 266 |
测试的结果有点奇怪。。。。。。。
可能跟一些其他的因素也有关系。。。比如DB的状态,比如浏览网页对CPU的占用
以上是关于vb.net 多线程 访问界面控件的主要内容,如果未能解决你的问题,请参考以下文章