RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 989792
Accepted
Aldmi
Aldmi
Asked:2020-06-06 12:29:04 +0000 UTC2020-06-06 12:29:04 +0000 UTC 2020-06-06 12:29:04 +0000 UTC

C# AspNetCore。数据处理的并行化。如何让它变得更好

  • 772

您好,在处理 AspNetCore 2.2 上的 Web 服务的到达数据之前,需要执行一项任务。

该服务启动多达 100 个通过 POST 请求接收数据的并行设备。我不会描述设备如何处理这些数据。

在处理这些数据之前有一项任务要做。例如,在输入中,有一个字符串类型的字段“名称”,其值为“MyLongName”。工程师制定了如何转换此字符串的规则。

  1. 如果超过限制修剪线
  2. 在正确的位置插入子字符串
  3. 更改案例
  4. ...

那些。构建了一个动作管道来处理该类型。

public class MiddleWareInData<TIn> : IDisposable
{
    public List<StringHandlerMiddleWare> StringHandlers { get; }
    public List<DateTimeHandlerMiddleWare> DateTimeHandlers { get; }

    private void HandleInvoke(IEnumerable<TIn> datas)
    {
        foreach (var data in datas)
        {
            //ОБРАБОТЧИКИ String
            Parallel.ForEach(StringHandlers, (stringHandler) =>
            {
                //Псевдо код обработки !!!
                var str = "Начальная строка";          //Найденное свойство в типе через рефлексию
                var res = stringHandler.Convert(str);  //Преобразование
                str = res;                             //перезаписали занчение свойства
            });

            //ОБРАБОТЧИКИ DateTime
            //foreach (var dateTimeHandler in DateTimeHandlers)
            //{

            //}
        }
    }
}


public class StringHandlerMiddleWare : BaseHandlerMiddleWare<string>
{

    public StringHandlerMiddleWare(StringHandlerMiddleWareOption option)
    {
        PropName = option.PropName;

        if (option.InseartStringConverterOption != null)
        {
            Converters.Add(new InseartStringConverter(option.InseartStringConverterOption));
        }
        if (option.LimitStringConverterOption != null)
        {
            Converters.Add(new LimitStringComverter(option.LimitStringConverterOption));
        }
        if (option.ReplaceEmptyStringConverterOption != null)
        {
            Converters.Add(new ReplaceEmptyStringConverter(option.ReplaceEmptyStringConverterOption));
        }
    }
}


public abstract class BaseHandlerMiddleWare<T>
{
    public string PropName { get; protected set; }
    protected readonly List<IConverterMiddleWare<T>> Converters = new List<IConverterMiddleWare<T>>();

    public virtual T Convert(T inProp)
    {
        var processedPrallel = Converters
            .AsParallel()
            .AsOrdered();

        foreach (var converter in processedPrallel)
        {
            inProp = converter.Convert(inProp);
        }
        return inProp;
    }
}

在 MiddleWareInData 类中,数据进入 HandleInvoke 方法,在该方法中它们开始按顺序处理,一次 1。我决定并行处理。最简单的方法是使用Parallel.ForEach,跨类型并行处理(一个数据单元的所有String类型都是并行处理的),在String类型的处理里面,启动了一个类型处理流水线,也可以运行在使用 PLINQ 并行(保持转换器调用的顺序)。您还可以使用 Parallel.ForEach 并行开始迭代 stringHandler 的数据本身。

那些。我们得到一个从 1 开始并行处理的输入数据列表。在这个数据单元的处理程序中,所有字符串类型都是并行处理的。字符串处理管道也是并行的(保留调用的顺序)。

我考虑过使用 MapReduce,但处理结束时不需要 Reduce(卷积),最后会有与输入相同的数据列表,只有转换后的数据。这种方式并行化处理是正常的,还是需要手动限制线程数,比如Parallel.ForEach。或者也许在某处使用 Task-i。

我将举一个具体的例子来分析并行操作设备100个。每个设备接受一个包含 50 个项目的列表。每个元素由 10 个 Handler 处理(需要更改 10 个 String 类型) 每个元素的处理管道由 5 个阶段组成。

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    tym32167
    2020-06-06T17:34:56Z2020-06-06T17:34:56Z

    我真的不明白您将如何开始并行处理保序转换器。事实上,如果动作本身的顺序被保留,那么这不再是并行处理,而是顺序处理。

    我想你会发现这个例子很有帮助:

    假设有这样一个代表

    delegate string Process(ref string s);
    

    我为它添加了一些功能

    string AddStart(ref string s)
    {
        return s = $"START {s}";
    }
    
    string AddEndt(ref string s)
    {
        return s = $"{s} END";
    }
    
    
    string ToLower(ref string s)
    {
        return s = s?.ToLower();
    }
    

    在此之后,您可以组装一个用于处理字符串的管道

    Process addStart = AddStart;
    Process addEndt = AddEndt;
    Process toLower = ToLower;
    var process = addStart + addEndt + toLower;
    

    管道将通过顺序启动处理程序来工作,您可以像这样检查它

    var str = "My AwEsOmE string!"; 
    Console.WriteLine(process(ref str));
    

    输出将是这样的

    start my awesome string! end
    

    此外,对于多行的并行处理,您可以调用它

    foreach (var item in Enumerable.Range(0, 10)
                        .Select(x => $"NUMBER IS {x}")
                        .AsParallel()
                        .Select(x=>process(ref x)))
    {
        Console.WriteLine(item);                        
    }
    

    结果

    start number is 0 end
    start number is 1 end
    start number is 2 end
    start number is 3 end
    start number is 4 end
    start number is 5 end
    start number is 6 end
    start number is 7 end
    start number is 8 end
    start number is 9 end
    

    但在这种情况下,行是并行处理的,结果可以是任何顺序。例如,字符串start number is 1 end可以被处理并出现在字符串之前的结果中start number is 0 end。如果需要保留输出中输入行的顺序,可以添加AsOrdered()

    foreach (var item in Enumerable.Range(0, 10)
                        .Select(x => $"NUMBER IS {x}")
                        .AsParallel()
                        .Select(x=>process(ref x))
                        .AsOrdered())
    {
        Console.WriteLine(item);                        
    }
    

    输出将被排序

    start number is 0 end
    start number is 1 end
    start number is 2 end
    start number is 3 end
    start number is 4 end
    start number is 5 end
    start number is 6 end
    start number is 7 end
    start number is 8 end
    start number is 9 end
    

    至于管道本身的并行化,正如我所说,既然你可以严格在前一个操作完成后开始下一个操作,那么你有一个串行管道,而不是并行管道,你不能为同一条线路运行转换器平行。

    还要记住,添加多线程并不总是会带来更快的性能。例如,如果您向线程发送大量小操作,那么处理器只会在线程之间进行切换,因为在线程之间切换是一项昂贵的操作。

    仅当您确定自己在做什么时,手动限制线程数也是值得的。默认调度程序足够聪明,通常可以信任它来完成​​这项工作。

    因此,如果你在输入端有一组行,而且行数很多,我会冷静地将这组委托给并行 PLINQ,并且不会发明任何东西。使传送带的台阶平行是没有意义的。此外,如果您想要速度并且您有很多转换规则并且字符串本身很大,那么可能首先,您需要寻找优化管道本身的方向,因为对字符串的任何编辑都会创建一个新字符串并在其上花费时间,与字符串的长度成正比。我建议朝那个方向看,也许调用 StringBuilder 而不是字符串,或者只是一个字符数组。但无论如何,任何优化都必须经过权衡、衡量并证明它在战斗条件下确实有效。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5