u-sql 作业非常慢,当我添加 .NET 调用时

u-sql job is very slow, when i add a .NET call

代码执行超过 2000 个小文件 (~10-50 Kb) ~ 1 分钟非常快。并行度 = 5.

@arenaData =
    EXTRACT col1, col2, col3
    FROM @in
    USING Extractors.Tsv(quoting : true, skipFirstNRows : 1, nullEscape : "\N", encoding:Encoding.UTF8);

@res =
    SELECT col1, col2, col3  
    FROM @arenaData;
    OUTPUT @res
    TO @out
    USING Outputters.Csv();

但如果我像这样更改代码,大约需要 1 小时

@arenaData =
    EXTRACT col1, col2, col3
    FROM @in
    USING Extractors.Tsv(quoting : true, skipFirstNRows : 1, nullEscape : "\N", encoding:Encoding.UTF8);

@res =
    SELECT
         col1.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) AS col1_converted,
, col2, col3

    FROM @arenaData;
    OUTPUT @res
    TO @out
    USING Outputters.Csv();

为什么.NET调用这么慢?我需要将源 CSV 文件中的日期格式转换为 "yyyy-MM-dd HH:mm:ss"?我怎样才能有效地做到这一点?

很高兴听到您现在的表现越来越好!

您的作业在超过 2800 个非常小的文件上运行,使用在托管代码中执行的表达式,而不是像 U-SQL 中一些更常见的 C# 表达式那样转换为 C++。

这会导致以下问题:

  1. 您以一定数量的 AU 开始工作。每个 AU 然后启动一个 YARN 容器来执行你的部分工作。这意味着容器需要完全初始化,这需要一些时间(您可以在 Vertex Execution View 中看到它作为创建时间)。现在这需要一点时间,如果你的顶点做一些大量的处理,那不是那么多的开销。不幸的是,在您的情况下,处理小文件的速度非常快,因此开销很大。

  2. 如果顶点只执行系统生成的代码,我们将这些代码生成为 C++ 代码,那么我们可以在没有重新初始化时间的情况下重用容器。不幸的是,由于遗留了潜在的工件,我们无法重用通过托管运行时执行的通用用户代码。所以在那种情况下我们需要重新初始化容器,这将花费时间(超过 2800 次)。

现在,根据您的反馈,我们正在改进我们的重新初始化逻辑(如果您不对内联 C# 表达式做任何花哨的事情,我们仍然可以重新初始化)。此外,一旦我们可以在单个顶点内处理多个小文件而不是每个顶点一个文件,它就会变得更好。

您的解决方法是增加文件的大小并尽可能避免自定义代码(当然并非总是可能)出现在太多的顶点中。