ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 2535|回复: 3

[求助] 请教VSTO插件的多线程处理

[复制链接]

TA的精华主题

TA的得分主题

发表于 2016-1-28 14:45 | 显示全部楼层 |阅读模式
用SynchronizationContext异步提取后台数据库的数据的时候是否会有效率差异?

由于数据库比较大,提取的数据也比较多。为了避免用户界面死锁的情况,写了一个DataFetcher的类,通过其来异步从后台数据库提取大量数据。测试发现提取50万的数据需要耗时2小时。但如果不采用异步方式的花,只需要15~30分钟左右。是否异步会有执行效率的差异?求高手看看代码。

  1. Imports System.Data
  2. Imports System.ComponentModel
  3. Imports System.Threading


  4. Namespace Core

  5.     ''' <summary>
  6.     ''' Provides data for DataFecher.Fetched event.
  7.     ''' </summary>
  8.     Public Class FetchedEventArgs
  9.         Inherits CancelableEventArgs

  10.         Private _data As Object

  11.         ''' <summary>
  12.         ''' Gets the fetched data. Returns null if fetching failed.
  13.         ''' </summary>
  14.         ReadOnly Property Data As Object
  15.             Get
  16.                 Return _data
  17.             End Get
  18.         End Property

  19.         ''' <summary>
  20.         ''' Initializes the new instance with data object.
  21.         ''' </summary>
  22.         Friend Sub New(ByVal data As Object)
  23.             MyBase.new()
  24.             _data = data
  25.         End Sub
  26.     End Class

  27.     ''' <summary>
  28.     ''' The delegation which occurs when trying to fetch data asynchronously.
  29.     ''' </summary>
  30.     ''' <param name="cnn">The connection string.</param>
  31.     ''' <param name="cmd">The command text.</param>
  32.     ''' <returns>The data object.</returns>
  33.     Public Delegate Function DataFetchingCallback(ByVal cnn As String, ByVal cmd As String) As Object

  34.     ''' <summary>
  35.     ''' Represents an object which can fetch data asynchronously.
  36.     ''' </summary>
  37.     Public Class DataFetcher
  38.         Private myThread As Thread
  39.         Private _cnn As String
  40.         Private _cmd As String
  41.         Private _context As SynchronizationContext
  42.         Private _fetching As DataFetchingCallback

  43.         ''' <summary>
  44.         ''' Occurs when DataFetcher.Fetch method was completed no matter successfully or failed.
  45.         ''' </summary>
  46.         ''' <param name="sender">The DataFetcher object which raises this event.</param>
  47.         ''' <param name="e">Event data.</param>
  48.         Public Event Fetched(ByVal sender As Object, ByVal e As FetchedEventArgs)

  49.         ''' <summary>
  50.         ''' Gets or sets the asynchronous callback to fetch data.
  51.         ''' </summary>
  52.         Property FetchingHandler As DataFetchingCallback
  53.             Get
  54.                 Return _fetching
  55.             End Get
  56.             Set(ByVal value As DataFetchingCallback)
  57.                 _fetching = value
  58.             End Set
  59.         End Property

  60.         ''' <summary>
  61.         ''' Gets or sets the connection string for data fetching.
  62.         ''' </summary>
  63.         Property ConnectionString As String
  64.             Get
  65.                 Return _cnn
  66.             End Get
  67.             Set(ByVal value As String)
  68.                 _cnn = value
  69.             End Set
  70.         End Property

  71.         ''' <summary>
  72.         ''' Gets or sets the command text for data fetching.
  73.         ''' </summary>
  74.         Property CommandText As String
  75.             Get
  76.                 Return _cmd
  77.             End Get
  78.             Set(ByVal value As String)
  79.                 _cmd = value
  80.             End Set
  81.         End Property

  82.         ''' <summary>
  83.         ''' Indicates whether the DataFetcher is fetching data now.
  84.         ''' </summary>
  85.         ReadOnly Property IsBusy As Boolean
  86.             Get
  87.                 Return IsNothing(myThread) = False AndAlso myThread.IsAlive
  88.             End Get
  89.         End Property

  90.         ''' <summary>
  91.         ''' Gets or sets the SynchronizationContext.
  92.         ''' </summary>
  93.         Property Context As SynchronizationContext
  94.             Get
  95.                 Return _context
  96.             End Get
  97.             Set(ByVal value As SynchronizationContext)
  98.                 _context = value
  99.             End Set
  100.         End Property

  101.         ''' <summary>
  102.         ''' Aborts the data fetching process.
  103.         ''' </summary>
  104.         Sub Abort()
  105.             If Me.IsBusy = False Then Return

  106.             myThread.Abort()
  107.             myThread = Nothing

  108.             Dim e As New FetchedEventArgs(Nothing)
  109.             e.Cancel = True
  110.             e.Message = "Aborted"

  111.             Me.OnFetched(e)

  112.         End Sub

  113.         ''' <summary>
  114.         ''' Checks DataFetcher whether it is ready to be called.
  115.         ''' </summary>
  116.         Protected Sub CheckForIlegal()
  117.             If IsNothing(Me.FetchingHandler) Then
  118.                 Throw Exceptions.Create("{0}.FechtingHandler can't be null.", Me.GetType.FullName)
  119.             End If

  120.             If IsNothing(Me.Context) Then
  121.                 Throw Exceptions.Create("{0}.Context can't be null.", Me.GetType.FullName)
  122.             End If

  123.             If String.IsNullOrEmpty(Me.ConnectionString) Then
  124.                 Throw Exceptions.Create("{0}.ConnectionString can't be empty.", Me.GetType.FullName)
  125.             End If

  126.             If String.IsNullOrEmpty(Me.CommandText) Then
  127.                 Throw Exceptions.Create("{0}.CommandText can't be empty.", Me.GetType.FullName)
  128.             End If

  129.             If Me.IsBusy Then
  130.                 Throw Exceptions.Create("{0}.Fetch can't be executed when busy.", Me.GetType.FullName)
  131.             End If
  132.         End Sub

  133.         ''' <summary>
  134.         ''' Starts to fetch data asynchronously.
  135.         ''' </summary>
  136.         Sub Fetch()
  137.             Me.CheckForIlegal()

  138.             myThread = New Thread(AddressOf Me.Start)
  139.             Dim ab As New AsyncBody With
  140.                 {
  141.                     .context = Me.Context,
  142.                     .cmd = Me.CommandText,
  143.                     .cnn = Me.ConnectionString,
  144.                     .fetching = Me.FetchingHandler
  145.                 }

  146.             myThread.Start(ab)
  147.         End Sub

  148.         ''' <summary>
  149.         ''' The embeded parameter passed to async thread.
  150.         ''' </summary>
  151.         Private Structure AsyncBody
  152.             ''' <summary>
  153.             ''' The SynchronizationContext which will accept result.
  154.             ''' </summary>
  155.             Public context As SynchronizationContext
  156.             ''' <summary>
  157.             ''' The command text.
  158.             ''' </summary>
  159.             Public cmd As String
  160.             ''' <summary>
  161.             ''' The connection string.
  162.             ''' </summary>
  163.             Public cnn As String
  164.             ''' <summary>
  165.             ''' The delegation of fetching data.
  166.             ''' </summary>
  167.             Public fetching As DataFetchingCallback
  168.         End Structure

  169.         ''' <summary>
  170.         ''' The embeded parameter passed to current thread.
  171.         ''' </summary>
  172.         Protected Structure AsyncResult
  173.             ''' <summary>
  174.             ''' If True, the fetching was failed. Otherwise, False.
  175.             ''' </summary>
  176.             Public cancel As Boolean
  177.             ''' <summary>
  178.             ''' The description of exception.
  179.             ''' </summary>
  180.             Public message As String
  181.             ''' <summary>
  182.             ''' The fetched data object.
  183.             ''' </summary>
  184.             Public result As Object
  185.         End Structure

  186.         ''' <summary>
  187.         ''' Starts to fetch data on an async thread.
  188.         ''' </summary>
  189.         ''' <param name="obj">The AsyncBody object which will be passed DataFetcher.FetchingHandler.</param>
  190.         ''' <remarks/>
  191.         Protected Sub Start(ByVal obj As Object)
  192.             Dim ab = CType(obj, AsyncBody)

  193.             Dim res = New AsyncResult With {.cancel = False, .message = ""}

  194.             Try
  195.                 res.result = ab.fetching.Invoke(ab.cnn, ab.cmd)
  196.             Catch ex As Exception
  197.                 res.cancel = True
  198.                 res.message = ex.Message
  199.                 res.result = Nothing
  200.             End Try

  201.             ab.context.Post(AddressOf Me.Post, res)
  202.         End Sub

  203.         ''' <summary>
  204.         ''' Returns current thread to handle fetched data.
  205.         ''' </summary>
  206.         ''' <param name="state">The AsyncResult object which will be used by DataFetcher.FetchedHandler.</param>
  207.         ''' <remarks></remarks>
  208.         Protected Sub Post(ByVal state As Object)
  209.             Dim ar = CType(state, AsyncResult)
  210.             Dim e As New FetchedEventArgs(ar.result)
  211.             e.Cancel = ar.cancel
  212.             e.Message = ar.message
  213.             Me.OnFetched(e)
  214.         End Sub

  215.         ''' <summary>
  216.         ''' Raises DataFetcher.Fetched event.
  217.         ''' </summary>
  218.         Protected Sub OnFetched(ByVal e As FetchedEventArgs)
  219.             RaiseEvent Fetched(Me, e)
  220.         End Sub

  221.     End Class

  222. End Namespace
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2016-1-28 14:54 | 显示全部楼层
代码继续

  1.     ''' <summary>
  2.     ''' The interface for cancelable event arguments.
  3.     ''' </summary>
  4.     Public Interface ICancelable
  5.         ''' <summary>
  6.         ''' Indicates the subsequent process need to be cancelled or not.
  7.         ''' </summary>
  8.         Property Cancel As Boolean
  9.         ''' <summary>
  10.         ''' The reason for cancellation.
  11.         ''' </summary>
  12.         Property Message As String
  13.     End Interface

  14.     ''' <summary>
  15.     ''' Provides data for cancelable event.
  16.     ''' </summary>
  17.     Public Class CancelableEventArgs
  18.         Inherits System.EventArgs
  19.         Implements ICancelable

  20.         Private _cancel As Boolean, _message As String

  21.         ''' <summary>
  22.         ''' Indicates whether next process should be cancelled or not.
  23.         ''' </summary>
  24.         Public Property Cancel As Boolean Implements ICancelable.Cancel
  25.             Get
  26.                 Return _cancel
  27.             End Get
  28.             Set(ByVal value As Boolean)
  29.                 _cancel = value
  30.             End Set
  31.         End Property

  32.         ''' <summary>
  33.         ''' The reason for cancellation.
  34.         ''' </summary>
  35.         Public Property Message As String Implements ICancelable.Message
  36.             Get
  37.                 Return _message
  38.             End Get
  39.             Set(ByVal value As String)
  40.                 _message = value
  41.             End Set
  42.         End Property
  43.     End Class


  44.     ''' <summary>
  45.     ''' A class to get tailor-made exception.
  46.     ''' </summary>
  47.     Public Class Exceptions

  48.         ''' <summary>
  49.         ''' Gets an xml string which explores the attributes of an exception.
  50.         ''' </summary>
  51.         Shared Function Explore(ByVal ex As Exception) As String
  52.             Dim x = <Exception Message=<%= ex.Message %>
  53.                         StackTrace=<%= ex.StackTrace %>
  54.                     />
  55.             If String.IsNullOrEmpty(ex.Source) = False Then x.SetAttributeValue("Source", ex.Source)
  56.             If IsNothing(ex.TargetSite) = False Then x.SetAttributeValue("TargetSite", ex.TargetSite.Name)

  57.             If ex.InnerException IsNot Nothing Then x.Add(XElement.Parse(Explore(ex.InnerException)))

  58.             Return x.ToString(SaveOptions.OmitDuplicateNamespaces)
  59.         End Function

  60.         ''' <summary>
  61.         ''' Prompts the Exception to user through MsgBox.
  62.         ''' </summary>
  63.         Shared Sub Prompt(ByVal ex As Exception, ByVal severity As Severity)
  64.             Select Case severity
  65.                 Case Core.Severity.None
  66.                     MsgBox(Extract(ex), MsgBoxStyle.Information)
  67.                 Case Core.Severity.Warning
  68.                     MsgBox(Extract(ex), MsgBoxStyle.Exclamation)
  69.                 Case Core.Severity.Warning
  70.                     MsgBox(Extract(ex), MsgBoxStyle.Critical)
  71.             End Select
  72.         End Sub

  73.         ''' <summary>
  74.         ''' Extracts the message and caster from an Exception.
  75.         ''' </summary>
  76.         Shared Function Extract(ByVal ex As Exception) As String
  77.             Dim s As String = ""
  78.             Dim e As Exception = ex

  79.             Do While Not IsNothing(e)
  80.                 If IsNothing(e.TargetSite) = False Then
  81.                     s = e.TargetSite.DeclaringType.FullName.Bracket(SpecialChar.BracketType.Brace) +
  82.                         SpecialChar.Dot + e.TargetSite.Name.Bracket(SpecialChar.BracketType.Brace)
  83.                     Exit Do
  84.                 End If
  85.                 e = e.InnerException
  86.             Loop

  87.             If String.IsNullOrEmpty(s) Then Return ex.Message

  88.             Return ex.Message + vbCr + vbCr + s
  89.         End Function

  90.         ''' <summary>
  91.         ''' Creates an Exception with inner exception and formatting message.
  92.         ''' </summary>
  93.         Shared Function Create(ByVal innerEx As Exception, ByVal format As String, ByVal ParamArray args() As Object) As Exception
  94.             Dim s = String.Format(format, args)
  95.             Return New Exception(s, innerEx)
  96.         End Function

  97.         ''' <summary>
  98.         ''' Creates an Exception with string format and arguments.
  99.         ''' </summary>
  100.         Shared Function Create(ByVal format As String, ByVal ParamArray args() As Object) As Exception
  101.             Return New Exception(String.Format(format, args))
  102.         End Function

  103.     End Class
复制代码

TA的精华主题

TA的得分主题

发表于 2016-1-28 16:08 来自手机 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
多线程异步,若电脑只能使用单个cpu,系统实际只是通过时间切片来模拟…不断切换会消耗资源…这时如果你盲目增加线程,只会得不偿失…若只为空出前台界面操作线程,应只开一个取数线程即可…没看代码,但你描述说的时间差异来看,你可能因为切换线程导致性能大幅下降…

TA的精华主题

TA的得分主题

发表于 2016-2-4 08:12 | 显示全部楼层
你要是去csdn上发这种帖子,肯定会被喷。
谁告诉你多线程一定比单线程快的?
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-5-16 03:02 , Processed in 0.036283 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表