【Grasshopper进阶】TaskCapableComponent vs Parallel.For 该怎么选?Grasshopper多线程进阶

本文比较了Grasshopper中TaskCapableComponent与Parallel.For在多线程应用上的区别。通过具体实例展示了两种方法的实现过程及性能表现。

TaskCapableComponent vs Parallel.For 该怎么选?

在Rhino6更新之后,Grasshopper加入了一个新的API —— TaskCapableComponent,使得电池对多线程有了更深度的支持。官方也早在2018年就做了文档和简单的例子,让大家能够更好的针对使用这个组件进行开发(官方例子链接)。

以下Grasshopper简称GH

不过官方的例子有点奇怪,为什么我算一个斐波那契数列还要多线程?这玩意儿多线程有啥意义?再进一步说,由于GH的整个画布的单线程架构,我在这个电池内部做计算密集型为什么不直接一个Parallel.For解决还需要实现这么复杂的接口?TaskCapableComponent与Parallel.For到底有什么区别?下面就一一解答。

关于为什么官例要用斐波那契数列,为什么这玩意儿要多线程,有什么意义,这个点放在最后说,因为当把TaskCapableComponent和Parallel.For它俩的区别说完之后,其原因就不言自明了。

注意: 以下代码均需要使用System.Threading.Tasks命名空间,即

using System.Threading.Tasks;

本文所有代码详见 https://codechina.youkuaiyun.com/bwkair/taskcapablevsparallel


Task Capable Component 要怎么实现

首先来看如何实现一个TaskCapableComponent:(笔者这里就不用官例的斐波那契数列了,采用一个很常规的Thread.Sleep()来实现)

  1. 首先第一步创建一个Grasshopper电池项目

    在这里插入图片描述

  2. 将新建立的GH电池类的继承由

    public class TaskCapableComponentExampleComponent : GH_Component
    

    改为

    public class TaskCapableComponentExampleComponent : GH_TaskCapableComponent<string>
    

    其中,string是每个线程任务执行完成后的返回值的类型,可以认为是等同于电池输出的数据类型。为什么会多出这个?

    因为GH多线程电池是基于C#中的Task类架构的,主要运算部分会被封装成一个Task类来进行分发。由于我们在GH内做的除开“在Rhino窗口进行图形预览绘制”以外的操作,都是有数据需要输出的,即我们希望使用多线程执行的任务是需要有数据返回的,而这个有返回值的Task类“就是需要用Task<T>”泛型类来封装,此时T就是返回的值的类型。

    总之,需要在GH电池的输出端输出什么类型的数据,这个T就是对应的类型

    更多有关于Task类的知识参照微软官方链接,此处不进行展开。

  3. 现在我们已经完成了一个支持多线程的电池架构。


“就这?”


需要做的改动当然不止于此了。目前仅仅是完成了“架构”部分的改动,电池是支持多线程了,但是我们的代码并没有真正地“实现多线程”。

实现多线程需要对电池的主运算部分SolveInstance()进行相应的重构。下面是开发文档的说明:

We will want to break the current flow of a component’s SolveInstance method into three distinct steps:

  1. Collect input data
  2. Compute results on given data
  3. Set output data

—— Steve Baer and Scott Davidson @Rhino Dev. Docs

译:

(要实现TaskCapableComponent的设计,)我们希望把原来电池的SolveInstance内部的程序流重组成为具有3个十分明显特征的步骤:

  1. 从输入端获取数据
  2. 由获取的数据运行所需要的计算
  3. 将计算结果输出

要我说,这其实是废话,因为本质上非多线程电池的对数据处理的逻辑简直是一模一样。我们先把非多线程的电池代码放上

protected override void RegisterInputParams(GH_InputParamManager pManager)
{
   
   
    pManager.AddIntegerParameter("Seconds", "s", "", GH_ParamAccess.item);
}

protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
   
   
    pManager.AddTextParameter("Output", "o", "", GH_ParamAccess.item);
}
protected override void Solv
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值