文章描述了一个在开发VSTOExcel加载项时遇到的问题,即由于网络延迟导致UI卡顿。作者尝试了VB.NET的异步操作但未解决问题,因为VB.NET的异步本质上仍是单线程。最终,通过引入委托和多线程,成功解决了UI阻塞问题。此外,文章还提到了单线程异步和多线程异步的适用场景,强调了根据任务类型选择合适的方法以优化性能。
摘要由CSDN通过智能技术生成
这几天做 excel 加载项时遇到一个问题,对话框弹窗显示后,需要等待网络数据的返回来填充 ListBox 控件,由于网络延迟问题,整个窗体连带 Excel 一起白屏卡顿 5-10秒,体验感极差。
这个问题其实在网络编程中是最常见的,通常都是采用 post 异步操作。于是我在 vb 中引用了 Task 异步载入数据,但问题依旧。查阅资料后原来是 vb.net 异步是单线程的,IO 繁忙阻塞了后续代码的执行。在
郑广学
老师的指点下,采用 vb 委托回调的概念,果然解决了这个痛点。
-
打开 Visual Studio 2017/2019/2021
-
创建一个 Excel VSTO 外接程序的新项目
-
添加一个 功能区(可视化设计器),编译器创建 Ribbon1.vb
-
点击工具面板增加一个按钮
-
添加一个 Windows 窗体,在窗体里添加 RichText 控件
代码文件 Ribbon1.vb,设置按钮弹窗响应
Imports Microsoft.Office.Tools.Ribbon
Public Class Ribbon1
Private Sub Button1_Click(sender As Object, e As RibbonControlEventArgs) Handles Button1.Click
Dim DW As New Form1
DW.Show()
End Sub
End Class
代码文件 Form1.vb, 声明委托、多线程、回调
Public Class Form1
Public Delegate Sub UpdateText(ByVal txt As String) '定义一个空委托,只有名字和参数
Private LoadText As UpdateText '声明一个委托类型变量
Private Sub TextSet(ByVal txt As String) '定义函数,将参数 txt 存入 RichText 控件中
Me.RichTextBox1.Text = txt
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim thId1 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
LoadText = AddressOf TextSet '当函数载入内存后,将其指针存到变量 LoadText
Dim sthread As New Threading.Thread( '创建第二线程并载入匿名函数
Sub()
Dim thId2 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
Threading.Thread.Sleep(5000) '模拟网络延迟 5 秒
Dim res As String = $"当前线程号:{thId2},来自 Web 的问候" '读到网络数据
Me.Invoke(LoadText, res) '在第二线程中执行回调函数
End Sub
sthread.Start()
RichTextBox1.Text = $"当前线程号:{thId1},数据载入中,请稍候..."
End Sub
End Class
找到原因了,单线程异步也可以避免阻塞,但是我把 Task.Delay() 时间设置的太短,此时载入窗口的主线程任务还没完成,造成阻塞。
Imports System.Threading.Tasks
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim thId1 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
Dim p As Task = LoadWebTextAsync()
RichTextBox1.Text = $"当前线程号:{thId1},数据载入中,请稍后..."
End Sub
Async Function LoadWebTextAsync() As Task
Await Task.Delay(5000)
Dim thId2 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
RichTextBox1.Text = $"当前线程号:{thId2},来自 Web 的问候!"
End Function
End Class
使用单线程异步和多线程异步使用原则:IO 密集型,如读取网络数据,此时 CPU 闲置率高,用单线程异步主要不产生阻塞,程序性能更高。多线程异步适合 计算密集型,如处理一百万行数据,此时 CPU 占用率高,启用多核心的 CPU 可以提高程序性能。
本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发。
其中委托的BeginInvoke方法以及回调函数最为常用。
而 I/O线程可能容易遭到大家的忽略,其实在开发多线程系统,更应该多留意I/O线程的操作。特别是在ASP.NET开发当中,可能更多人只会留意在客户端使用Ajax或者在服务器端使用UpdatePanel。其
VSTO 是微软用于开发 Office 插件的一种技术,跟 VBA 比较起来,VSTO 开发更加简单,功能更加强大。本系列博客介绍利用 VSTO 开发 Excel 插件的方法。VSTO 开发的 Excel 插件 (Add-in)是 COM 加载项的一种。新的开发技术可以使用 Excel Web Add-In。
开发环境:Visual Studio 2019
新建一个 Excel VSTO Add-In 项目,因为 Visual Studio 2019 支持的项目类型较多,通过界面的开发语言、平台和项目类型进