我正在运行一个循环,该循环评估用户对超过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函数,而直接将字符串解析为可执行文件,而不对每个对象求值。有任何加快循环的提示吗?
答案 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)。