I wrote Designscript code to create multiple road routes, there are several performance issues:
I use loop to create them one by one, but if parallel operations can be done, I can create them in parallel.
for each route, it’s consists of many curves, I use loop to create them one by one. I can also create them in parallel if Parallel operations can be done.
import clr
import time
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
from System.Threading.Tasks import *
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)
def drawlines(lstpt):
outlines = []
for idx, pt in enumerate(lstpt):
if idx > 0:
line = Line.ByStartPointEndPoint(lstpt[idx - 1], pt)
outlines.append(line)
return outlines
lstpoints = IN[0]
start = time.time()
if IN[1]:
threadResult = lstpoints.AsParallel().Select(lambda sublst: drawlines(sublst)).ToList()
out = threadResult
else:
out = []
for sublst in lstpoints:
out.append(drawlines(sublst))
# Calculate Run-time
time = ("%s s" % (time.time()-start))
OUT = time, out
Better to time this with TuneUp as it will incorporate the other aspects of the Dynamo environment (ie: preview and data marshaling) if I’m not mistaken.
Also a note to anyone who visits later: This will likely not work with Generative Design (requires 6+ cores for running each of the Dynamo Core engines concurrently) or Revit interactions (limited to one thread as a DB). Worth testing anyway.
Hello @Vladimir
it’s necessary to convert the result to List (to avoid overwriting the previous return variable)
import clr
import time
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
from System.Threading.Tasks import *
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)
def intrs(elA, elB):
return elA.IntersectAll(elB)
lstpoints = IN[0]
o = IN[1]
start = time.time()
res =[]
tst = 0
#oo = o
#ls = lstpoints
for ls,oo in zip(lstpoints,o):
threadResult = ls.AsParallel().Select(lambda l: (intrs(l,oo))).ToList()
res.append(threadResult)
tst=tst+1
time = ("%s s" % (time.time()-start))
OUT = time, res
All works, but i feel, that for ls,oo in zip(lstpoints,o): in my code is bad for balancing quenue.
The idea is to send independant chunks (like [a[0], b[0]],[a[1], b[1]] ) to different threads.
Example:
The “a” chunks contains Rooms solids. The “b” chunks contains some walls solids.
Can i ask you, how to push two arguments into PLINQ?
Found .Zip here:
var a = new int[] { 1, 2 };
var b = new int[] { 3, 4 };
foreach (var n in a.Zip(b, (x, y) => x + y))
{
// enumerates 4 (1 + 3), 6 (2 + 4)
}
And the question is how to apply it in PLINQ in Python. (Without Python loops)
Attached sample dyn.
UPD: found out, that we can’t use ConcurrentQueue with PLINQ multithreading. The question is how we can make thread safe PLINQ to protect data and avoid data corruption. Thank you!
for AsParallel() with ConcurrentQueue I used this code
import sys
import clr
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
from System.Collections.Concurrent import ConcurrentQueue
from System.Collections.Generic import List
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
def test(*args):
lstPoints = [p.Centroid() for p in args]
points = Point.PruneDuplicates(lstPoints)
return points
ziplst = zip(*IN)
out = []
lstRtn = ConcurrentQueue[System.Array[DS.Point]]()
#
ziplst.AsParallel()\
.WithDegreeOfParallelism(System.Environment.ProcessorCount)\
.WithExecutionMode(System.Linq.ParallelExecutionMode.ForceParallelism)\
.ForAll(lambda e : lstRtn.Enqueue(test(*e)))
OUT = lstRtn
Hello @c.poupin,
Noticed errors if try to switch to CPython3 in your previous post:
AttributeError : ‘zip’ object has no attribute ‘AsParallel’.
Do you think its possible to use PLINQ in CPython?