【问题标题】:VB optimize loop avoid with an Evaluate()VB 使用 Evaluate() 优化循环避免
【发布时间】:2018-12-27 16:37:29
【问题描述】:

我正在运行一个循环来评估用户提供的超过 150k 个对象的输入。用户将信息设置为“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

然后我将结果存储在一个矩阵中,该矩阵最后粘贴到一个 Excel 文件中。有没有一种方法可以将要评估的字符串转换为函数的返回值?我想避免使用 Eval 函数并直接解析可执行文件中的字符串,而不是为每个对象评估它。关于加速循环的任何提示?

【问题讨论】:

  • 如果同一请求发生多次,您可以存储该值而不是再次评估它。
  • 就代码而言,最重要的是在Evaluate(...) 调用中计算的内容,但缺少了这一点。我们需要一个minimal reproducible example。
  • stackoverflow.com/q/1707854/11683 向您发送了正确的方向,但您使用 VB 编写代码这一事实可能会限制您的选择。
  • 我投票结束这个问题作为离题,因为它要求审查。请将其发送至Code Review,然后关闭此问题。

标签: vb.net loops optimization foreach evaluate


【解决方案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))

【讨论】:

    【解决方案2】:

    评估功能只是计算机本身的资源。它非常适合使用 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)。

    【讨论】:

      猜你喜欢
      • 2017-06-04
      • 2019-11-17
      • 2015-07-29
      • 2020-06-15
      • 2020-05-27
      • 2023-03-27
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多