Using parfeval to call eval function not working - why?

25 views (last 30 days)
First of all, I know using eval at all is generally bad practice, but in this case it's kind of necessary. I have a piece of software where users (other programmers) need to be able to write their own functions to be called at a particular time. It includes a GUI where, before running the software, they can browse to the function that they want to run at a particular point in the process. The name of the function is saved to the GUI model and I use eval to make sure the correct function is run when the time comes. This software has been used for a couple years without issue so the eval aspect of this works just fine for our case.
Now I'm trying to update the software so that this function, that was generated by the user, is run on a parallel pool. An abstraction of my code would look like this:
P = parpool(1);
Q = parallel.pool.DataQueue;
afterEach(Q, @disp);
run_command = "test_func(Q)"; %This is a test function I created, normally this would contain a string with the user's function name and inputs
success = parfeval(P, @eval, 1, run_command);
I then have the function test_func defined as follows:
function test_func(Q)
send(Q, 1);
pause(2);
send(Q, 2);
pause(2);
send(Q, 3);
end
This code above does not display the numbers as expected. When I look at 'success', the FevalFuture, it shows an error message of:
"Incorrect use of '=' operator. Assign a value to a variable using '=' and compare values for equality using '=='." at line 39 of this file: C:\Program Files\MATLAB\R2021b\toolbox\parallel\cluster\+parallel\+internal\+queue\evaluateRequest.m.
I'm not sure if this file is part of the eval function or part of the parfeval function. So I guess I'm wondering why my original code which simply looked like
eval(run_command);
works just fine, but putting this into parfeval suddenly throws this random error?
If I change the code to pass test_func into parfeval directly, it works just fine.
P = parpool(1);
Q = parallel.pool.DataQueue;
afterEach(Q, @disp);
run_command = "test_func(Q)"; %This is a test function I created, normally this would contain a string with the user's function name and inputs
success = parfeval(P, @test_func, 1, Q);
So it seems like using @eval as the function passed to parfeval is causing some kind of issue. My question is why? Is this a combination that just doesn't work or is there something wrong with the way I am calling it?
Any insight would be appreciated, as I'm new to parallel computing. Thank you!

Accepted Answer

Walter Roberson
Walter Roberson on 27 Jun 2022
Transparency violation. parfor and parfeval need to know the names of the functions at analysis time so that it can copy the code to the workers before evaluation starts.
  8 Comments
Lisa Taylor
Lisa Taylor on 28 Jun 2022
Edited: Lisa Taylor on 28 Jun 2022
@Edric Ellis Sorry for being unclear, I may just not understand correctly how fetchOutputs works. Your code does work when I run it as you posted, but you have to use the fetchOutputs function to actually see the display on the screen. And what it displays is not the results of each disp function, but the result of "ok" set in the wrpaper function. Doesn't this mean that you are fetching the outputs and displaying them all at once, at the end, after the full evaluate_run_command is done running on the worker? And that the outputs in test_func themselves are never being displayed?
In real life, the function I am running on the worker takes about 20-30 minutes to run (depending on how the user has customized it). It will be returning data over Q every few seconds, and that data needs to be used immediately to update a GUI displayed on the screen (the update_gui function called by afterEach). It would not work for my purposes if its outputs (which are not explicitly returned outputs, but are simply changes displayed on the GUI) cannot be seen until the entire parfeval function is done running.
I also wasn't sure that fetchOutputs would even work for my real project, since the update_gui function being run with afterEach does not explicitly return any outputs. It simply updates the gui's model and uses drawnow to update the gui objects. I guess this may not be an issue since disp does not explicitly return an output either?
I will look into str2func, I don't think I've used that one before. It may have application elsewhere even if it doesn't help here. Thank you again for your help!
Lisa Taylor
Lisa Taylor on 28 Jun 2022
Edited: Lisa Taylor on 28 Jun 2022
@Edric Ellis After submitting the previous comment I changed the wrapper function to not return the "ok" variable, and test_func to have longer pauses in between displaying numbers, and it does actually display the 1 and 2 as the f unction executes, not all at the end. Rather than returning the logical 1 "ok" variable. So perhaps my concern is wrong and this will work! I'm only trying to understand this in my head, rather than just testing it out, because to test out the real software I have to schedule time in a lab on some specific hardware, I can only test it out with these test functions on my own computer. So sorry if I am making up problems that aren't there simply because I don't fully understand matlab parallel computing yet.

Sign in to comment.

More Answers (0)

Categories

Find more on Asynchronous Parallel Programming in Help Center and File Exchange

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!