c4d threading runs only on one core and is slower than single threaded



  • put this code in a python generator and place any polygon object under it. run it single threaded , then increase the maxThreads.

    it is significant slower when maxThreads > 1.

    import c4d
    import math
    import time
    #Welcome to the world of Python
    
    
    
    RootNull = c4d.BaseObject(c4d.Onull)
    
    
    
    def currStateToObject(source):
    	
    	return c4d.utils.SendModelingCommand(
    		 command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
    		 list = [source],
    		 mode=c4d.MODELINGCOMMANDMODE_ALL,
    		 bc=c4d.BaseContainer(),
    		 doc = doc)[0]   
    
    def connectDelete(source):
     
    	return c4d.utils.SendModelingCommand(
    		 command = c4d.MCOMMAND_JOIN,
    		 list = [source],
    		 mode=c4d.MODELINGCOMMANDMODE_ALL,
    		 bc=c4d.BaseContainer())[0] 
    
    	
    class ThreadedCut(c4d.threading.C4DThread):
    
    	def TestBreak(self):
    		return None
    
    	def __init__(self, sList):    
    		print "thread init"
    		self.sList = sList
    	
    	def Main(self):
    		print "thread start"
    		for s in self.sList:
    			
    			self.CutObject(s)
    		print "thread finish"
    	
    	def CutObject(self,s):
    		
    		global objReference
    	   
    		# create a copy 
    	
    		obj = objReference.GetClone()
    		
    		
    		allPoints = obj.GetAllPoints()
    	
    	
    		bbox = obj.GetRad()  
    		
    		p1 = c4d.Vector(bbox.x*10,s,bbox.z*10)
    		v1 = c4d.Vector(bbox.x*10,0,bbox.z*-10)
    		p2 = c4d.Vector(bbox.x*-10,0,bbox.z*10)
    		v2 = c4d.Vector(bbox.x*-10,0,bbox.z*-10)
    		
    		data = c4d.BaseContainer()
    		data.SetVector(c4d.MDATA_KNIFE_P1, p1)
    		data.SetVector(c4d.MDATA_KNIFE_P2, p2)
    		data.SetVector(c4d.MDATA_KNIFE_V1, v1)
    		data.SetVector(c4d.MDATA_KNIFE_V2, v2)
    		
    		c4d.utils.SendModelingCommand(c4d.MCOMMAND_KNIFE, [obj], bc=data, doc=doc)
    		newPoints = obj.GetAllPoints()
    		
    		pointSelection = obj.GetPointS()
    		for i in range(len(allPoints),len(newPoints)):
    			pointSelection.Select(i)
    			
    		bc = c4d.BaseContainer()
    		bc.SetData(c4d.MDATA_CONVERTSELECTION_LEFT, 0)
    		bc.SetData(c4d.MDATA_CONVERTSELECTION_RIGHT, 1)
    		bc.SetData(c4d.MDATA_CONVERTSELECTION_TOLERANT, False)
    		c4d.utils.SendModelingCommand(c4d.MCOMMAND_CONVERTSELECTION, [obj], bc=bc, doc=doc)
    		c4d.utils.SendModelingCommand(c4d.MCOMMAND_EDGE_TO_SPLINE, [obj])
    		if obj.GetDown():
    			return obj.GetDown().InsertUnder(RootNull)
    		return None
    
    
    
    	
    def chunkIt(seq, num):
    	"""
    	https://stackoverflow.com/questions/2130016/splitting-a-list-into-n-parts-of-approximately-equal-length/37414115
    	"""
    	avg = len(seq) / float(num)
    	out = []
    	last = 0.0
    
    	while last < len(seq):
    		out.append(seq[int(last):int(last + avg)])
    		last += avg
    
    	return out   
    
    
    
    objReference = None
    
    
    def main():
    	
    	global objReference
    	runningThreads = 0    
    	starttime = time.time()
    	
    	obj = currStateToObject(op.GetDown())  
    	objReference = obj
    	
    	maxThreads = 1
    	
    	minHeight = -200
    	maxHeight = 200
    	offset = 0.5
    	maxSlices = 10000
    	sliceList= []
    	
    	
    	for i in range(0,maxSlices):
    		s =  minHeight + i*offset
    		if (s <= maxHeight and s < obj.GetRad().y*2):            
    			sliceList.append(s)
    		else:
    			break
    			
    	chunks = chunkIt(sliceList,maxThreads)    
    	
    	tList = []
    	
    	for c in chunks: 
    		print len(c),len(sliceList)
    		t = ThreadedCut(c)        
    		tList.append(t)
    		
    	print "threadlist rdy"
    	for t in tList:       
    		t.Start()
    
    	for t in tList:      
    		t.Wait(True)
    	  
    	
    	spline = connectDelete(RootNull)
    	spline[c4d.SPLINEOBJECT_TYPE] = 3
    	spline[c4d.SPLINEOBJECT_CLOSED] = True
    	
    	end = time.time()
    	print end-starttime
    	return spline

  • Global Moderator

    Hi @pyr,

    In Python, there is a GIL which do not allow Python by design to execute something in parallel.

    In Cinema 4D all our functions (so everything which is in the c4d python module) is "GIL safe" in order to avoid any issue with Python memory.
    So in Cinema 4D thread are designed for doing GUI, or background stuff.
    Moreover, keep in mind creating a Thread have a cost in term of time (to create, execute, delete them).

    Finally, I would like to point you to multiprocessing vs multi-threading.

    Note that since it's more an algorithm problem than an issue related to our API, we can only provide you hints.

    btw, I also turned your topic as a question. See Q&A New Functionality.
    Cheers,
    Maxime.