Creating 1000's of objects is slower than I thought it should be. Based on a suggestion here it could be related to name collision checking so I thought I would look into it. Here is some data, and the script I used. As a reference, I also did a simple name comparison between all pairs of objects using an extremely sloowwwww loop in python. That is almost 100 times faster than the creation (which is happening in C, right?) So something else is going on.
Both of these times are clearly proportional to n^2, so it does seem to be checking the new shape against all the others. The times don't change much when I use icospheres (80 faces) instead of cubes(6 faces), so it's based on objects, not faces. That rules out some kinds of checking.
My question is, first, why (actually) is it so slow, and second, how can I create thousands of objects (e.g. cubes) in a script, without waiting minutes each time I tweak some parameter, while still seeing all of them once it's done. I'm using 2.74.
NOTE: I did some spot checking by running the loop only once, or over and over with the same nxy, and there does not appear to be contamination of the measurements due to memory issues (see my comments about garbage collection in the script).
import bpy import numpy as np import time wxy = 15.0 sx, sy, sz = 0.9, 0.9, 0.2 t_create_list, t_check_list = ,  n_create_list, n_check_list, n_same_list = , ,  nxy_list = [10, 15, 20, 25, 30, 35, 40] listlen = len(nxy_list) for ii, nxy in enumerate(nxy_list): rcube = 0.5 * wxy / float(nxy) q = 0.5 * wxy * (1. - 1. / float(nxy)) xyc = np.linspace(-q, q, nxy) XC, YC = np.meshgrid(xyc, xyc) ZC = np.zeros_like(XC) centers = zip(XC.flatten(), YC.flatten(), ZC.flatten()) start = time.clock() for ic, center in enumerate(centers): ok = bpy.ops.mesh.primitive_cube_add(radius=rcube, location=center) ao = bpy.context.active_object ao.scale = (sx, sy, sz) stop = time.clock() time_to_create = stop - start so = bpy.context.selectable_objects number = len(so) same, count = 0, 0 start = time.clock() for i in range(number): #very sloowwwww way to compare names for j in range(i, number): count += 1 if so[i].name == so[j].name: same += 1 stop = time.clock() time_to_check = stop - start t_create_list.append(time_to_create) t_check_list.append(time_to_check) n_create_list.append(number) n_check_list.append(count) n_same_list.append(same) for thing in so: thing.select = True bpy.ops.object.delete(use_global=True) # but can I invoke garbage collection inside this loop? # for example, can I somehow do a save .blend which should cause garbage collection? print("number ", ii+1, " of ", listlen) t_create_list = [round(thing,4) for thing in t_create_list] t_check_list = [round(thing,4) for thing in t_check_list] lists = [n_create_list, t_create_list, n_check_list, t_check_list, n_same_list] save = np.array(lists,dtype='float') for thing in lists[1:]: save = np.vstack((save, thing)) np.save("check_it_out", save)