VB优化循环避免使用Evaluate()

时间:2018-07-19 13:48:33

标签: vb.net loops optimization foreach evaluate

我正在运行一个循环,该循环评估用户对超过15万个对象的输入。用户将信息设置为“ obj.Name”,“ obj.Path”,“ obj.Date”等形式,其中可能还包含诸如“ IIf(obj.Params> 5,1,0)”之类的逻辑评估。然后将它作为字符串提供给程序。

我使用了Evaluate()函数,并且效果很好,只是速度很慢。处理所有要素大约需要6小时。我在想是否有办法将请求的信息以某种方式转换为简单的可执行文件,并避免在整个循环中使用Evaluate表达式(它会根据用户请求的数据数量运行* 150k)。

这是我正在运行的循环的示意图:

For Each Object in ObjectsList
    For Each UserRequest in Requests
        ResultsMatrix(i,j) = Evaluate(Requests(i))
        j += 1
    Next
    i += 1
Next

然后我将结果存储在一个Matrix中,该矩阵最后粘贴到Excel文件中。有没有一种方法可以对要计算为函数返回值的字符串进行某种处理?我想避免使用Eval函数,而直接将字符串解析为可执行文件,而不对每个对象求值。有任何加快循环的提示吗?

2 个答案:

答案 0 :(得分:1)

可能值得考虑将请求写入一组函数,并使用.NET CodeDom编译器将其构建为DLL。然后,您可以加载程序集,使用反射找到合适的函数并将其放入数组中,然后使用反射调用它们-这样一来,您将调用.NET代码,它应该快得多。一些(不完整的)代码可以帮助您从我已经完成此工作的项目开始...

        Private Function CombineCode() As String

            Dim ret As New System.Text.StringBuilder
            ret.AppendLine("Imports System")
            ret.AppendLine("Imports Microsoft.VisualBasic")
            ret.AppendLine()
            ret.AppendLine("Namespace " & MainNamespace)
            ret.AppendLine("Public Class " & MainClassName)

            For Each e In _Entries
                ret.AppendLine(e.Value.Code)
            Next

            ret.AppendLine("End Class")
            ret.AppendLine("End Namespace")

            Return ret.ToString
        End Function

        Private Function Compile(Code As String) As Assembly
            'Dim d As New Dictionary(Of String, String)
            'd.Add("langversion", "14")
            Dim VBP As New Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider()

            Dim PM As New System.CodeDom.Compiler.CompilerParameters
            'PM.GenerateInMemory = True
            PM.GenerateExecutable = False
            PM.OutputAssembly = IO.Path.Combine(_Path, GenerateFileName() & ".dll") ' "Generated.dll"
            PM.MainClass = MainClassName
            PM.IncludeDebugInformation = True


            Dim ASM As System.Reflection.Assembly
            For Each ASM In AppDomain.CurrentDomain.GetAssemblies()
                Try
                    If ASM.Location <> "" Then PM.ReferencedAssemblies.Add(ASM.Location)
                Catch
                End Try
            Next

            PM.ReferencedAssemblies.Add("System.Web.dll")

            'Get compilation results
            Dim Results As System.CodeDom.Compiler.CompilerResults
            Results = VBP.CompileAssemblyFromSource(PM, Code)

            'Show possible compilation errors
            Dim Err As System.CodeDom.Compiler.CompilerError
            For Each Err In Results.Errors
                Throw New SyntaxErrorException("Error N. " & Err.ErrorNumber &
            " Message: " & Err.ErrorText & " Line " & Err.Line & " in code " & vbCrLf & Code)
            Next

            Return Results.CompiledAssembly

        End Function
        Private Sub FindMethods()
            Dim dt = (From t In _LatestAssembly.GetTypes() Where t.Name = MainClassName).Single
            For Each e In _Entries.Values
                e.Method = dt.GetMethod(e.MethodName)
            Next
        End Sub


Assembly = Assembly.LoadFrom(System.IO.Path.Combine(Path, sd.LatestAssemblyFile))

答案 1 :(得分:0)

“评估”功能只是计算机本身上的资源。这是使用Parallel.For的绝佳选择。

在这种情况下,j是隐含索引。

For Each Object in ObjectsList

    Parallel.For(0, Requests.Length, New ParallelOptions(), Sub(j, loopState)
           ResultsMatrix(i,j) = Evaluate(Requests(j))
        End Sub
    )
    i += 1
Next

请注意,Requests(i)被反复调用并产生相同的结果,所以我假设您的意思是Requests(j)。