栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 云计算 > 云平台

使用TaskFactory类实现MapReduce功能

云平台 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用TaskFactory类实现MapReduce功能

简介

在多线程编程中,MapReduce 是最为常用的一种模型。在C#中有TaskFactory类,可以实现此功能。本文就通过一个实例,介绍具体的工作原理。同时,还引入了CancellationTokenSource类,用于中止整个MapReduce任务。

基本原理

MapReduce 分为 Map 和 Reduce两个过程,在Map中进行并行计算,在Reduce中对并行计算的结果进行汇总。这两步在TaskFactory中,分别可以使可以有以下实现方法:

  • Map factory.StartNew(task, source.Token)
    需要注意的是,在调用此方法后,代码就会开始并行执行,并返回任务的句柄(Task对象);
  • Reduce factory.ContinueWhenAll(tasks, reduceTask, token);
    此方法会等所有任务都结束后才会执行 reduceTask 任务,同时由于 token 的引入,如果任何一个任务取消了,就会引发 AggregateException 异常。
示例代码与结果

本示例演示了使用10个线程分别生成10个[0, 199] 的随机整型(共100个),一旦在随机生成时值为0,则会调用 source.Cancel() 函数。在完成所有任务后,求所有值的平均值。为了演示一定的时间变化,中间加入了一些延时函数。

        // 代码比较长,但只有两个部分:变量定义与初始化 和 任务执行
        // 来源:https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-6.0
public void MapReduceExample()
{
    
    // Define the cancellation token.
    var source = new CancellationTokenSource();
    List> tasks = new List>();
    TaskFactory factory = new TaskFactory(source.Token);
    Random random = new Random();
    tbLogs.Text = "";

    // Map Task
    for (int taskId = 0; taskId < 10; taskId++)
    {
        Func fi = () =>
        {
            print($"Mapper: Task start.");
            Thread.Sleep(100);
            int[] values = new int[10];
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = random.Next(0, 200);
                if (values[i] == 0 && !source.Token.IsCancellationRequested)
                {
                	// 如果这里取消了,那么当前的任务就会结束,使用聚类方法调用时会触发AggregateException 异常
                    source.Cancel();
                    print($"Mapper: Cancelling.");
                }
            }
            print($"Mapper: Task Done.");
            return values;
        };
        // 添加任务到tasks中,实际上这里任务已经启动了 StartNew 就会启动一个新线程。
        tasks.Add(factory.StartNew(fi, source.Token));
    }
    Thread.Sleep(1);
    print("Main: tasks.Count" + tasks.Count);

    // Reduce Task 
    Func[], double> func = (results) =>
    {
        print($"Reducer: Calculating overall mean...");
        return results.Sum(r => r.Result.Sum()) / (double)results.Sum(r => r.Result.Length);
    };

    
    try
    {
    	// 此时 tasks 中的线程已经都在运行中了,如果中间时间过长的话,会有部分任务已经完成了
        print($"Main: Begin to calculate...");
        Task fTask = factory.ContinueWhenAll(tasks.ToArray(), func, source.Token);
        print($"Main: The mean is {fTask.Result}.");
    }
    catch (AggregateException ae)
    {
        print($"Main: ae = " + ae.Message);
        foreach (Exception e in ae.InnerExceptions)
        {
            if (e is TaskCanceledException tcx)
                print($"Main: Unable to compute mean: {tcx.Message}");
            else
                print($"Main: Exception: " + e.GetType().Name);
        }
    }
    finally
    {
        source.Dispose();
    }

    void print(string msg)
    {
        var newstr = $"{DateTime.Now:HH:mm:ss.fff}-{Thread.CurrentThread.ManagedThreadId}: {msg}n";
        this.Dispatcher.BeginInvoke(() => { tbLogs.Text += newstr; });
        Debug.WriteLine(newstr);
    }
运行结果
  • 正常结果:返回分步和统计的结果。

  • 运行取消:当随机值为0时,会取消整个操作。

扩展

如果不是等所有的Reducer结束,而是只要有一个就结束,可以调用 ContinueWhenAny 方法。不过这些由于使用了 CancellationTokenSource,所以会引发 ObjectDisposedException 异常,代码如下所示:

// 代码比较长,但只有两个部分:变量定义与初始化 和 任务执行
// 来源:https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-6.0
public void MapReduceExample()
{
    
    // Define the cancellation token.
    var source = new CancellationTokenSource();
    List> tasks = new List>();
    TaskFactory factory = new TaskFactory(source.Token);
    Random random = new Random();
    tbLogs.Text = "";

    // Map Task
    for (int taskId = 0; taskId < 10; taskId++)
    {
        Func fi = () =>
        {
            print($"Mapper: Task start.");
            Thread.Sleep(100);
            int[] values = new int[10];
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = random.Next(0, 200);
                try
                {
                    if (values[i] == 0 && !source.Token.IsCancellationRequested)
                    {
                        source.Cancel();
                        print($"Mapper: Cancelling.");
                    }
                }
                catch (ObjectDisposedException ex) { print("ObjectDisposedException: " + ex.Message); }
                catch (Exception ex) { print(ex.ToString()); }
            }
            print($"Mapper: Task Done.");
            return values;
        };
        tasks.Add(factory.StartNew(fi, source.Token));
    }
    Thread.Sleep(1);
    print("Main: tasks.Count" + tasks.Count);

    // Reduce Task 
    Func[], double> func = (results) =>
    {
        print($"Reducer: Calculating overall mean...");
        return results.Sum(r => r.Result.Sum()) / (double)results.Sum(r => r.Result.Length);
    };

    
    try
    {
        print($"[Main]: Begin to calculate...");
        // Task fTask = factory.ContinueWhenAll(tasks.ToArray(), func, source.Token);
        Task fTask = factory.ContinueWhenAny(tasks.ToArray(), (res) => { return (double)res.Result.Sum(); }, source.Token);
        print($"[Main]: The mean is {fTask.Result}.");
    }
    catch (AggregateException ae)
    {
        print($"Main: ae = " + ae.Message);
        foreach (Exception e in ae.InnerExceptions)
        {
            if (e is TaskCanceledException tcx)
                print($"Main: Unable to compute mean: {tcx.Message}");
            else
                print($"Main: Exception: " + e.GetType().Name);
        }
    }
    finally
    {
        source.Dispose();
    }

    void print(string msg)
    {
        var newstr = $"{DateTime.Now:HH:mm:ss.fff}-{Thread.CurrentThread.ManagedThreadId}: {msg}n";
        this.Dispatcher.BeginInvoke(() => { tbLogs.Text += newstr; });
        Debug.WriteLine(newstr);
    }
}

其他

PS. 在测试中出现以下代码,原因未知,暂时未解决。


详细信息如下

System.Resources.MissingSatelliteAssemblyException
未能找到或无法加载用于回退区域性“en”的名为“Microsoft.VisualStudio.DesignTools.SurfaceDesigner.resources.dll, Version=17.0.0.0, PublicKeyToken=b03f5f7f11d5a3a”的附属程序集。这通常是安装问题。请考虑重新安装或修复该应用程序。
   在 System.Resources.ManifestBasedResourceGroveler.HandleSatelliteMissing()
   在 System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark)
   在 System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark)
   在 System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
   在 System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
   在 System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   在 Microsoft.VisualStudio.DesignTools.SurfaceDesigner.DesignerTapStringTable.GetStringTable[T]()
   在 Microsoft.VisualStudio.DesignTools.WpfSurfaceDesigner.Views.WpfSurfaceProcessContext.GetDesignerTapStringTable()
   在 Microsoft.VisualStudio.DesignTools.SurfaceDesigner.Documents.SurfaceIsolation.SurfaceProcessContext.InitializePipeline()
   在 Microsoft.VisualStudio.DesignTools.SurfaceDesigner.Documents.SurfaceIsolation.SurfaceProcessContext.FinishSurfaceProcessCreation(DateTime start, Boolean forcePlatformOnly)
   在 Microsoft.VisualStudio.DesignTools.SurfaceDesigner.Documents.SurfaceIsolation.SurfaceProcessContext.d__105.MoveNext()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 Microsoft.VisualStudio.DesignTools.XamlSurfaceDesigner.Views.IsolatedSurfaceImageHost.d__67.MoveNext()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   在 Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)

System.AggregateException
发生一个或多个错误。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/897581.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号