Notifications
Clear all

[Closed] Using .NET BackgroundWorker with MAXscript

Hello guys. I’m tring to figure out few things about this technique right now:

  • Can I use more than one BackgroundWorker to speed up parallelable calculations?

  • Is there any way to modify objects within BackgroundWorker? Right now just adding even a simple modifier from background usually crashes MAX. Maybe there’s some technique to isolate object’s copy within distinct thread?

  • Is there any way to stop BackgroundWorker correctly, so I can give it next assignment? Right now started threads stay busy (.isBusy == true) for a while after they complete their tasks. Or may be I should just start a new backgroundWorker, after previous one reports about its task completion?

Any help is mush appreciated.

19 Replies

you can not modify max objects on a background worker thread but you can use multithreading for non-max related things.
for example, i made a tool to batch resize texture maps in the scene where the resizing is done on multiple threads and then the bitmaptexture paths are all updated on the main thread.

as for stopping and starting BackgroundWorkers – in my example above i fill a queue of work items and each background thread just has a while loop that pops an item from the queue and does some work or just returns if there are no more items.

what exactly are you trying to accomplish?

Looks like I CAN modify object within BackgroundWorker
It seems that it’s just enough to disableSceneRedraw() before running BackgroundWorkers and enableSceneRedraw() back again after all BackgroundWorkers finished their tasks.
Here’s an example script that changes wirecolor and adds meshsmooth modifier to selected objects:

global threadArray, busyArr, DisableWindowsGhosting, mainThread
busyArr = #{}
procArr = #()
threadsCount = 8
clearListener()
threadArray = #()
fn testFn pArr =
(
)
fn UpdateThread val =
(
)
fn mainFunc pArr =
(
icount = 0
disableSceneRedraw()
while procArr.count != 0 or keyboard.escPressed do
(
cObj = procArr[1]
workerFound = false
for i=1 to threadsCount do
(
if not workerFound and procArr.count>0 do if not busyArr[i] do
(
dotCobj = dotNetMXSValue #(cObj,i)
threadArray[i] = undefined
gc()
threadArray[i] = dotnetobject “CSharpUtilities.SynchronizingBackgroundWorker”
threadArray[i].workerReportsProgress = true
dotNet.addEventHandler threadArray[i] “DoWork” testFn
dotNet.addEventHandler threadArray[i] “ProgressChanged” UpdateThread
threadArray[i].RunWorkerAsync dotCobj
workerFound = true
busyArr[i] = true
)
)
if workerFound do deleteItem procArr 1
format “Proc count:%\n” procArr.count
)
enableSceneRedraw()
)
fn testFn pArr =
(
procNode = pArr.argument.value[1]
cThread = pArr.argument.value[2]
procNode.wirecolor = random black white
addmodifier procNode (meshSmooth())
threadArray[cThread].reportProgress 100 cThread
)
fn UpdateThread val =
(
busyArr[val.userstate] = false
)
mainThread = dotnetobject “CSharpUtilities.SynchronizingBackgroundWorker”
dotNet.addEventHandler mainThread “DoWork” mainFunc
for i in selection do append procArr i
mainThread.RunWorkerAsync()

Nice, but does it really improve performance?
I tested your example with a hundred of midpoly teapots. Half a million polys overall.
The goal is to get total face area of selected objects.
Timings are:
Time: 1.594sec. Mem: 7093136L – background workers
Time: 1.142sec. Mem: 7499944L – for s in selection do …

Looks like I CAN modify object within BackgroundWorker

well there you go! i completely forgot about the CSharpUtilities.SynchronizingBackgroundWorker but i agree with Serejah’s questioning of the performance benefit.

the other question i have is – what happens when a user interacts with max while this is all going on?
scene redraw may be disbaled but what if they open some modal dialog, select items via selection set, try to create a new object, press the delete key, attempt to save or open a file, etc?

1 Reply
(@serejah)
Joined: 10 months ago

Posts: 0

Guess we can lock main thread using progressStart / progressEnd to prevent that

Ok so we’re back to performance then. Is it actually worth it? Do you have comparison numbers with what your trying to do?

Too bad I won’t be able to share my results, because I’m working on a commercial project with very strict NDA.
But I’ll let you know at least some abstract information when I’ll get any results.

in general case using of multi-threading is not safe in 3DS MAX system when you work with scene or MAX UI.

that means the code example abode (with applying MeshSmooth modifier) can’t work!
(if someone says it works, I never believe)

At least in MAX 2018 it does. Check yourself.

1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

I do not need it. I know how the system works. The fact that your code works is just a coincidence, but it can not give an advantage anyway

there is no sense in what you do…
what is the reason of using BackgroundWorker?
the reason is to do something on background when the main thread is busy by doing some heavy job. In your case the heavy job is “smooth mesh” operations. it takes 99% of the time and performance. And(!) it can be done only in the main thread (because MeshSmooth is not designed for multi-threading). There is absolutely nothing to do on background

Page 1 / 2