| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2323 人关注过本帖, 1 人收藏
标题:请教:用VBA代码运行超大数据量的时间太久,该如何解决?
只看楼主 加入收藏
sapphirechin
Rank: 1
等 级:新手上路
帖 子:3
专家分:0
注 册:2015-11-21
结帖率:100%
收藏(1)
已结贴  问题点数:20 回复次数:6 
请教:用VBA代码运行超大数据量的时间太久,该如何解决?
有一个文本文件,500万行记录,每行三个数据。
代码先将该文本文件的数据,按行分别读入到三个数组中。
然后需要遍历整个数组,做一个简单的计算。并把计算结果存储为字符串,每行字符串有500万个数据。
一次遍历完成后,将该行数据写到另一个文本文件中。
然后继续下一次遍历,共计80万次。

目前的硬件情况是:4G内存,core i5处理器。代码已经跑了快一个礼拜了,不知道何时会有个尽头。

请教各位高手,这样的VBA代码该如何优化能大幅度提升速度呢?附件是VBA代码,望指点!
VBA代码.rar (1.09 KB)
搜索更多相关主题的帖子: 文本文件 记录 如何 字符串 处理器 
2015-11-21 09:39
hjxlj
Rank: 10Rank: 10Rank: 10
来 自:江西
等 级:贵宾
威 望:14
帖 子:292
专家分:1519
注 册:2013-6-25
收藏
得分:0 
楼主不能把问题描述清楚一点吗?实在不行,加我企鹅号775420425交流。

本人QQ:775420425
2015-11-21 11:54
sapphirechin
Rank: 1
等 级:新手上路
帖 子:3
专家分:0
注 册:2015-11-21
收藏
得分:0 
回复 2楼 hjxlj
请问还需要描述哪些方面呢?
我已经将每个步骤都描述了,而且给出了代码?
不知道您还需要了解什么内容?
2015-11-21 15:07
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4941
专家分:30047
注 册:2008-10-15
收藏
得分:10 
看了一下你的代码,你的代码里的循环次数是: 500W*500W=25万亿次

好吧,
使用了VB吧【秋枫萧萧】的双线程方法,CPU占用率比较高,也会比很慢,实在是运算次数太多了。

以下为代码的版权申明部分
'非原创的代码部分已标明原作者及出处。其余部分皆为【秋枫萧萧】(百度ID:hhyjq007)自己研究而成
'感谢老汉、TGY、IZERO等等为VB6完美、稳定多线程铺平道路的前辈们!
'若有任何疑问可到【VBGOOD论坛】或百度贴吧【VB吧】发帖交流!

[此贴子已经被作者于2015-11-22 17:57编辑过]


授人于鱼,不如授人于渔
早已停用QQ了
2015-11-22 10:17
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4941
专家分:30047
注 册:2008-10-15
收藏
得分:10 
Option Explicit
Private Sub Command1_Click()
Me.Cls
Print Now; "开始读取数据"
DoEvents
Call AP60First
Print Now; "读取数据完成,共计:"; RowCount; "行数据"
Print Now; "开始启动双线程运算"
DoEvents

'启动双线程
'                                                                                               线程函数                                  创建后立即运行
VBThreadHandle1 = CreateThread(ByVal 0&, ByVal 0&, AddressOf VBMTRun.Thread1, ByVal 0&, ByVal CREATE_DEFAULT, VBThreadID1)
VBThreadHandle2 = CreateThread(ByVal 0&, ByVal 0&, AddressOf VBMTRun.Thread2, ByVal 0&, ByVal CREATE_DEFAULT, VBThreadID2)
DoEvents

'VB6主线程一边傻等子线程全部结束一边睡大觉
Do Until (Thread1exit = 1 And Thread2exit = 1)
    DoEvents        '刷新界面,防止窗口卡顿
    Sleep 30        '睡大觉
Loop
Print Now; "运算完成,开始写结果"
DoEvents
Dim filePath As String
filePath = "d:\2.txt"
StrLine2 = Left(StrLine2, Len(StrLine2) - 1)  '去除该行字符串的结尾的逗号
Open filePath For Output As #1
       Print #1, StrLine1; StrLine2 '写入文本文件
Close #1
Print Now; "写结果完成"
End Sub

Sub AP60First()
Const CON_RECORD_COUNT As Long = 5000000
Dim filePath As String
filePath = "d:\1.txt"
Dim i As Long, j As Long, d As Single
ReDim X(1 To CON_RECORD_COUNT), Y(1 To CON_RECORD_COUNT), G(1 To CON_RECORD_COUNT)
'从txt加载到数组
Dim textSplit
Dim doCount As Long
doCount = 1
Dim rowText As String        
Open filePath For Input As #1        
Do While Not EOF(1)
   Line Input #1, rowText            
   If doCount >= 2 Then
      textSplit = VBA.Split(rowText, ",")
      X(doCount - 1) = textSplit(0)  '第一个数据导入
      Y(doCount - 1) = textSplit(1)  '第二个数据导入
      G(doCount - 1) = textSplit(2)  '第三个数据导入
   End If            
   doCount = doCount + 1
Loop        
Close #1
RowCount = doCount - 2
End Sub

-------VBMTRun-------------
Option Explicit

'定义线程句柄
Public VBThreadHandle1 As Long, VBThreadHandle2 As Long
'定义线程ID
Public VBThreadID1 As Long, VBThreadID2 As Long

'定义线程退出变量
Public Thread1exit As Long, Thread2exit As Long
Public RowCount As Long
Public X() As Single, Y() As Single, G() As Long
Public StrLine1 As String, StrLine2 As String

'************************************注意:VB6多线程必须以SUB MAIN为启动对象***************************************************
'***************************本示例中已经设置好了,自己使用时注意在工程——属性——启动对象中自行选择************************
Sub Main()
If AvoidReentrant = False Then       '防止主线程重复运行
    AvoidReentrant = True
        If App.PrevInstance Then        '防止程序重复运行
            MessageBox ByVal 0&, StrPtr("程序正在运行或未完全退出"), StrPtr("重复运行"), vbCritical
            Exit Sub
        Else
            InitCommonControls      '初始化通用控件
            GETVBHeader                 '获取VB数据头            
            Form1.Show     '在这里加载主窗体
        End If
End If
End Sub

Public Sub Thread1()        '子线程1
'***********************************(重要!)VB6线程环境初始化*************************************************
CreateIExprSrvObj 0&, 4&, 0&            'VB6运行库初始化
CoInitializeEx ByVal 0&, ByVal (COINIT_MULTITHREADED Or COINIT_SPEED_OVER_MEMORY)   'COM组件初始化
InitVBdll               '诱导VB6运行库内部其他部分的初始化
'***********************************(重要!)VB6线程环境初始化*************************************************
Thread1exit = 0
Dim i As Long
Dim j As Long, d As Long
For i = 1 To RowCount / 2        '这里有误差,这里只是测试一下
    If G(i) > 0 Then      
       For j = 1 To RowCount
           d = (X(i) - X(j)) ^ 2 + (Y(i) - Y(j)) ^ 2
           StrLine1 = StrLine1 & d & ","  '将计算结果组合成字符串,以逗号分隔
       Next     
     End If
Next i
Thread1exit = 1
CoUninitialize      '卸载COM组件(省掉也不会影响稳定性,但可能造成句柄或内存泄漏。为了养成好习惯,还是写上)
End Sub

Public Sub Thread2()        '子线程2
'***********************************(重要!)VB6线程环境初始化*************************************************
CreateIExprSrvObj 0&, 4&, 0&            'VB6运行库初始化
CoInitializeEx ByVal 0&, ByVal (COINIT_MULTITHREADED Or COINIT_SPEED_OVER_MEMORY)   'COM组件初始化
InitVBdll               '诱导VB6运行库内部其他部分的初始化
'***********************************(重要!)VB6线程环境初始化*************************************************
Thread2exit = 0
Dim i As Long
Dim j As Long, d As Long
For i = RowCount / 2 + 1 To RowCount            '这里有误差,这里只是测试一下
    If G(i) > 0 Then      
       For j = 1 To RowCount
           d = (X(i) - X(j)) ^ 2 + (Y(i) - Y(j)) ^ 2
           StrLine2 = StrLine2 & d & ","  '将计算结果组合成字符串,以逗号分隔
       Next     
     End If
Next i
Thread2exit = 1
CoUninitialize      '卸载COM组件(省掉也不会影响稳定性,但可能造成句柄或内存泄漏。为了养成好习惯,还是写上)
End Sub

--------VBMTInit-----------
不贴了,自己找去。

授人于鱼,不如授人于渔
早已停用QQ了
2015-11-22 11:39
sapphirechin
Rank: 1
等 级:新手上路
帖 子:3
专家分:0
注 册:2015-11-21
收藏
得分:0 
回复 5楼 风吹过b
非常感谢您的帮助!我现在就试试看.
另外想问一下,"--------VBMTInit-----------不贴了,自己找去。"是不是指下面还有代码需要我写的呢?
2015-11-23 08:39
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4941
专家分:30047
注 册:2008-10-15
收藏
得分:0 
你按 4 楼的提示去找,主要是这个文件是 【秋枫萧萧】(百度ID:hhyjq007) 写的,
我引用了他的东西,然后需要修改的内容也修改了,不修改的内容,最好去他的原贴找。
----------------
进度条的问题,因为我仅仅是测试,所以还没对这个内容测试一下,
其实,主线程可以访问子线程的专用公用变量,但同时只有有一个写。自己注意,如果需要同时读写,需要使用临界区。不建议。
进度条,可以设置一个子专用公用变量,子线程执行情况,写入这个变量,然后主线程等待过程时,只读取这个变量去取进度情况。


授人于鱼,不如授人于渔
早已停用QQ了
2015-11-23 11:53
快速回复:请教:用VBA代码运行超大数据量的时间太久,该如何解决?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.023517 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved