It seems that all our versions so far are WRONG.
(
print "V1"
start = timestamp()
seed(timestamp())
mem = heapfree
results = for i = 1 to 10000 collect i
for i = 1 to 10000 do swap results[i] (results[random 1 10000])
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
results = makeUniqueArray results
format "There are % duplicate results
" (10000-results.count)
)
processing: 0.012 seconds heap: 560240L
There are 5046 duplicate results
(
start = timestamp()
seed(timestamp())
mem = heapfree
results = for i = 1 to 10000 collect i
for i = 1 to 10000 do
(
swap results[i] results[random 1 10000]
)
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
results = makeUniqueArray results
format "There are % duplicate results
" (10000-results.count)
)
(
start = timestamp()
seed(timestamp())
mem = heapfree
results = for i = 1 to 10000 collect i
for i = 1 to 10000 do
(
local ind = random 1 10000
swap results[i] results[ind]
)
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
results = makeUniqueArray results
format "There are % duplicate results
" (10000-results.count)
)
processing: 0.012 seconds heap: 560240L
There are 4976 duplicate results
OK
processing: 0.015 seconds heap: 560264L
There are 0 duplicate results
OK
seems there is some problem with swap method. The first block of code does not work, while the second one does. Anyone have any ideas why this happens?
No ideia why it happens, but I’ve corrected my V5 version to use a local var for the index.
Btw… how about splitting the randomization in two threads? he he he check it out.
This is the V5 corrected:
(
print "V5"
gc()
start = timestamp()
seed(timestamp())
mem = heapfree
asize = 1000000
results = for i = 1 to asize collect i
for i = 1 to asize do
(
idx = random i asize
swap results[i] results[idx]
)
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
)
(
print "V6"
gc()
startg = timestamp()
seed(timestamp())
mem = heapfree
asize = 1000000
results = for i = 1 to asize collect i
fn dowork1 =
(
start = timestamp()
for i = 1 to results.count/2 do
(
idx = random i asize
swap results[i] results[idx]
)
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
)
fn dowork2 =
(
start = timestamp()
for i = (results.count/2)+1 to asize do
(
idx = random i asize
swap results[i] results[idx]
)
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
)
MainThread = dotnetobject "System.ComponentModel.BackGroundWorker"
print "MainThread"
dotNet.addEventHandler MainThread "DoWork" dowork1
--------------------
SecondaryThread = dotnetobject "System.ComponentModel.BackGroundWorker"
print "SecondaryThread"
dotNet.addEventHandler SecondaryThread "DoWork" dowork2
-----------------------
MainThread.RunWorkerAsync()
SecondaryThread.RunWorkerAsync()
endg = timestamp()
format "processing: % seconds heap: %
" ((endg - startg) / 1000.0) (mem-heapfree)
)
The results:
"V5"
processing: 1.428 seconds heap: 56074760L
OK
"V6"
"MainThread"
"SecondaryThread"
processing: 0.378 seconds heap: 56076304L
OK
processing: 0.591 seconds heap: 56076512L
processing: 0.592 seconds heap: 56076576L
Since the V6 is multithreaded I assume we have to sum the first processing, which is the global script execution with the highest of the two next processings times to have an accurate result, so in this case it would be something like 0.378 + 0.592 = 0.97
He he under 1 second
It does? but each thread is working on half the array… and my random is using i to 1000000 and not 1 to 1000000, so it should be ok, but I havent tested for duplicates with makeUniqueArray.
Well, you can add more and more threads as long as you have them I just used two for showing purposes Bring it on!
You can do multi-threaded like that!? Would this work on other intensive maxscripts, like getting alot of object positions or vert positions and whatnot?
Like break up a mesh into 2 vert sets, and send both off 2 Two CPUs and get them back?
Very cool stuff so far
Yeah, for sure, just check out a blog post by lonerobot where he gives a small intro and example for working with this class. The only thing I dont think you can do directly in maxscript is to get how many threads the cpu has, but you can write a custom dll for that or just use that runtime compiling that denisT does alot. That way, you could in theory get how many threads the cpu has, divide your array by that and assign that to each thread. Never tried it before except today with this example.
edit: forget all the above, here you go: sysinfo.cpucount (I’ve used it in iray Manager)
Awesome! yeah, I was going to say, I thought I saw a cpu count somewhere. I will have to look at this tonight/this weekend for sure
I wonder why Autodesk doesn’t have maxscripts run on all cores by default…?
gc()
ts = timestamp()
mem = heapfree
p=0
n=1000000
fn compareFN v1 v2=
(
ind=(random 2 n)
tmp=results[1] --always swap with index 1, doesnt matter, we have no index pointer here.
results[1]= results[ind]
results[ind]=tmp
--p=p+1
1 -- return 1 for the qsort function
)
results = for i = 1 to n collect i -- just generate a filler array
dmy=#()
dmy[2000]=0 -- sorting an array with count=2000 results in 1002004 itterations of the shuffle loop, array empty so almost no memory use.
qsort dmy compareFN -- abuse the qsort function to just internally swap the array values
--print results -- uncomment en set n=10 to see if the algorithm works
format "Time: %, Memory: %
" (timestamp()-ts) (mem-heapfree)
--print p --uncomment this and the p=p+1 in the function to see the number of shuffles
On my machine this is twice as fast as Lo’s winning solution (3.8 vs 7.9 sec) so if someone can confirm that it would be nice
It’s a bit of a weird method, I let qsort call it’s sort function. That function doesn’t sort but it shuffles the array and always returns a ‘1’.
Sorting an empty dummy array that is 2000 entries long results in 1002004 calls to the function. which is just over the number of iterations that is needed to shuffle or source array.
I suspect that qsort is calling the function in a more efficient way that doing it in a higher level loop.
edit: added a gc() to the script… seems to make it go even faster… 2.7s on my machine (8 core xeon, 5420 2.something GHz… so not really fast per single core )