diff --git a/GrasshopperAsyncComponent/Base/GH_AsyncComponent.cs b/GrasshopperAsyncComponent/Base/GH_AsyncComponent.cs
index 569a7a6..f955ce9 100644
--- a/GrasshopperAsyncComponent/Base/GH_AsyncComponent.cs
+++ b/GrasshopperAsyncComponent/Base/GH_AsyncComponent.cs
@@ -8,6 +8,9 @@ using Timer = System.Timers.Timer;
namespace GrasshopperAsyncComponent
{
+ ///
+ /// Inherit your component from this class to make all the async goodness available.
+ ///
public abstract class GH_AsyncComponent : GH_Component
{
public override Guid ComponentGuid { get => new Guid("5DBBD498-0326-4E25-83A5-424D8DC493D4"); }
@@ -30,12 +33,23 @@ namespace GrasshopperAsyncComponent
int Iterations = 0;
- public WorkerInstance BaseWorker { get; set; }
+ bool SetData = false;
List Workers;
+ List Tasks;
+
List CancelationSources;
+ ///
+ /// Set this property inside the constructor of your derived component.
+ ///
+ public WorkerInstance BaseWorker { get; set; }
+
+ ///
+ /// Optional: if you have opinions on how the default system task scheduler should treat your workers, set it here.
+ ///
+ public TaskCreationOptions? TaskCreationOptions { get; set; } = null;
protected GH_AsyncComponent(string name, string nickname, string description, string category, string subCategory) : base(name, nickname, description, category, subCategory)
{
@@ -61,8 +75,10 @@ namespace GrasshopperAsyncComponent
{
State++;
- if (State == Iterations)
+ if (State == Workers.Count)
{
+ SetData = true;
+ Workers.Reverse();
Rhino.RhinoApp.InvokeOnUiThread((Action)delegate
{
ExpireSolution(true);
@@ -74,28 +90,35 @@ namespace GrasshopperAsyncComponent
Workers = new List();
CancelationSources = new List();
+ Tasks = new List();
}
protected override void BeforeSolveInstance()
{
- if (State != 0) return;
+ if (State != 0 && SetData) return;
foreach (var source in CancelationSources) source.Cancel();
CancelationSources.Clear();
Workers.Clear();
Errors.Clear();
+ Tasks.Clear();
State = 0;
- Iterations = 0;
- base.BeforeSolveInstance();
+ }
+
+ protected override void AfterSolveInstance()
+ {
+ if (State == 0 && Tasks.Count > 0)
+ {
+ foreach (var task in Tasks) task.Start();
+ }
}
protected override void SolveInstance(IGH_DataAccess DA)
{
if (State == 0)
{
- Iterations++;
if (BaseWorker == null)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Worker class not provided.");
@@ -116,32 +139,50 @@ namespace GrasshopperAsyncComponent
var tokenSource = new CancellationTokenSource();
CurrentWorker.CancellationToken = tokenSource.Token;
CurrentWorker.Id = DA.Iteration.ToString();
- var CurrentRun = new Task(() => CurrentWorker.DoWork(ReportProgress, ReportError, Done), tokenSource.Token, TaskCreationOptions.LongRunning);
+ Task CurrentRun;
+ if (TaskCreationOptions != null)
+ {
+ CurrentRun = new Task(() => CurrentWorker.DoWork(ReportProgress, ReportError, Done), tokenSource.Token, (TaskCreationOptions)TaskCreationOptions);
+ }
+ else
+ {
+ CurrentRun = new Task(() => CurrentWorker.DoWork(ReportProgress, ReportError, Done), tokenSource.Token);
+ }
// Add cancelation source to our bag
CancelationSources.Add(tokenSource);
+
// Add the worker to our list
Workers.Add(CurrentWorker);
- CurrentRun.Start();
+ Tasks.Add(CurrentRun);
+
return;
}
- var test = DA.Iteration;
-
- Workers[DA.Iteration].SetData(DA);
-
- // Note we're decrementing the state here.
- if (--State == 0)
+ if (SetData)
{
- foreach (var (message, type) in Errors)
- {
- AddRuntimeMessage(type, message);
- }
+ if (Workers.Count > 0)
+ Workers[--State].SetData(DA);
- Message = "Done";
- OnDisplayExpired(true);
- Errors.Clear();
+ if (State == 0)
+ {
+ foreach (var (message, type) in Errors)
+ {
+ AddRuntimeMessage(type, message);
+ }
+
+ CancelationSources.Clear();
+ Workers.Clear();
+ Errors.Clear();
+ Tasks.Clear();
+
+ SetData = false;
+
+ Message = "Done";
+ //OnDisplayExpired(true);
+ OnDisplayExpired(false);
+ }
}
}
}
diff --git a/GrasshopperAsyncComponent/Base/IAsyncComponentWorker.cs b/GrasshopperAsyncComponent/Base/IAsyncComponentWorker.cs
index a470595..b0943c0 100644
--- a/GrasshopperAsyncComponent/Base/IAsyncComponentWorker.cs
+++ b/GrasshopperAsyncComponent/Base/IAsyncComponentWorker.cs
@@ -32,7 +32,7 @@ namespace GrasshopperAsyncComponent
///
/// This method is where the actual calculation/computation/heavy lifting should be done.
- /// Make sure you always check as frequently as you can if is cancelled. For an example, see the .
+ /// Make sure you always check as frequently as you can if is cancelled. For an example, see the .
///
/// Call this to report progress up to the parent component.
/// Call this to report errors up to the parent component.
diff --git a/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj b/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj
index a981acc..8a12863 100644
--- a/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj
+++ b/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj
@@ -63,7 +63,7 @@
-
+
diff --git a/GrasshopperAsyncComponent/SampleImplementations/SampleAsyncComponent.cs b/GrasshopperAsyncComponent/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs
similarity index 77%
rename from GrasshopperAsyncComponent/SampleImplementations/SampleAsyncComponent.cs
rename to GrasshopperAsyncComponent/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs
index 05e7703..35b1479 100644
--- a/GrasshopperAsyncComponent/SampleImplementations/SampleAsyncComponent.cs
+++ b/GrasshopperAsyncComponent/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace GrasshopperAsyncComponent.SampleImplementations
{
- public class SampleAsyncComponent : GH_AsyncComponent
+ public class Sample_PrimeCalculatorAsyncComponent : GH_AsyncComponent
{
public override Guid ComponentGuid { get => new Guid("DF2B93E2-052D-4BE4-BC62-90DC1F169BF6"); }
@@ -16,19 +16,19 @@ namespace GrasshopperAsyncComponent.SampleImplementations
public override GH_Exposure Exposure => GH_Exposure.primary;
- public SampleAsyncComponent() : base("Sample Async Component", "CYCLOMAXOTRON", "Meaningless labour.", "Samples", "Async")
+ public Sample_PrimeCalculatorAsyncComponent() : base("Sample Async Component", "PRIME", "Calculates the nth prime number.", "Samples", "Async")
{
- BaseWorker = new PrimeCalculator();
+ BaseWorker = new PrimeCalculatorWorker();
}
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
- pManager.AddIntegerParameter("Max iterations", "M", "How many useless cycles should we spin. Minimum 10, maximum 1000.", GH_ParamAccess.item);
+ pManager.AddIntegerParameter("N", "N", "Which n-th prime number. Minimum 1, maximum one million. Take care, it can burn your CPU.", GH_ParamAccess.item);
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
- pManager.AddTextParameter("Output", "O", "Will just say hello world after spinning.", GH_ParamAccess.item);
+ pManager.AddTextParameter("Output", "O", "The n-th prime number.", GH_ParamAccess.item);
}
}
@@ -75,7 +75,7 @@ namespace GrasshopperAsyncComponent.SampleImplementations
}
}
- public class PrimeCalculator : WorkerInstance
+ public class PrimeCalculatorWorker : WorkerInstance
{
int TehNthPrime { get; set; } = 100;
long ThePrime { get; set; } = -1;
@@ -120,24 +120,22 @@ namespace GrasshopperAsyncComponent.SampleImplementations
Done();
}
- public override WorkerInstance Duplicate() => new PrimeCalculator();
+ public override WorkerInstance Duplicate() => new PrimeCalculatorWorker();
public override void GetData(IGH_DataAccess DA, GH_ComponentParamServer Params)
{
- if (CancellationToken.IsCancellationRequested) return;
+ int _nthPrime = 100;
+ DA.GetData(0, ref _nthPrime);
+ if (_nthPrime > 1000000) _nthPrime = 1000000;
+ if (_nthPrime < 1) _nthPrime = 1;
- int _maxIterations = 100;
- DA.GetData(0, ref _maxIterations);
- if (_maxIterations > 1000000) _maxIterations = 1000000;
- if (_maxIterations < 10) _maxIterations = 10;
-
- TehNthPrime = _maxIterations;
+ TehNthPrime = _nthPrime;
}
public override void SetData(IGH_DataAccess DA)
{
if (CancellationToken.IsCancellationRequested) return;
- DA.SetData(0, $"Hello world. Worker {Id} has found for that the {TehNthPrime}th prime is: {ThePrime}");
+ DA.SetData(0, $"W_ID {Id}: {TehNthPrime}th prime is: {ThePrime}");
}
}