What is the alternative function for evalin?

조회 수: 34 (최근 30일)
Ammy
Ammy 2021년 8월 14일
답변: Jan 2021년 8월 17일
I want to improve the performance of my function.
  • Avoid functions such as eval, evalc, evalin, and feval(fname). Use the function handle input to feval whenever possible. Indirectly evaluating a MATLAB expression from text is computationally expensive.
I 'm using the following to read data from workspace to function file.
A= evalin('base','dataset');
Is there any alternative way for reading variables from workspace to Matlab function that is efficient.
  댓글 수: 2
Stephen23
Stephen23 2021년 8월 16일
"Is there any alternative way for reading variables from workspace to Matlab function that is efficient."
By far the most efficient approach (as well as being simpler, much more robust, and easier to debug) is to pass all data as input/output variables:
Better code design does not just mean swapping some function X for another mysteriously faster function Y with exactly the same behavior, it means actually designing your data and code following best-practices (following this forum is a good place to start learning those).
Walter Roberson
Walter Roberson 2021년 8월 16일
And see my newest test just posted here that shows passing parameters through multiple levels is faster.

댓글을 달려면 로그인하십시오.

채택된 답변

Walter Roberson
Walter Roberson 2021년 8월 14일
Shared variables are 2 to 5 times faster than evalin('base')
test_base()
ans = 5.7348e-06
ans = 2.7770e-06
function test_base
A = rand(1e7,1);
assignin('base', 'A', A);
timeit(@() via_evalin(), 0)
timeit(@() via_shared(), 0)
function B = via_evalin()
B = evalin('base', 'A');
end
function B = via_shared()
B = A;
end
end
  댓글 수: 7
Ammy
Ammy 2021년 8월 16일
Thank you.
Walter Roberson
Walter Roberson 2021년 8월 16일
It is a fair question to ask what the best performance is if you have multiple levels of calls.
The following code goes through 5 calling levels before doing the "work" (fetching the value and assigning to output). Exact timings depend upon the run, but it seems consistent that creating 5 levels of shared variables is the slowest of these three, and that passing as a parameter is the fastest.
In the earlier tests, sharing through one level of nested function was nearly indistinguishable from passing as parameters; this test tells us that there is a performance penalty to having to find the shared variable through multiple levels.
format long g
test_base();
t = 3×1
0.005531 0.00831 0.002545
function test_base
N = 500;
A = rand(1e7,1);
assignin('base', 'A', A);
t = zeros(3,1);
tic; for K = 1:N; via_evalin1(); end; t(1) = toc;
tic; for K = 1:N; via_shared1(); end; t(2) = toc;
tic; for K = 1:N; via_passed1(A); end; t(3) = toc;
t
cats = categorical({'evalin', 'shared variable', 'passed parameter'});
bar(cats, t);
function B = via_evalin1()
B = via_evalin2();
end
function B = via_evalin2()
B = via_evalin3();
end
function B = via_evalin3();
B = via_evalin4();
end
function B = via_evalin4();
B = via_evalin5();
end
function B = via_evalin5();
B = evalin('base', 'A');
end
function B = via_shared1()
B = via_shared2();
function B = via_shared2()
B = via_shared3();
function B = via_shared3();
B = via_shared4();
function B = via_shared4();
B = via_shared5();
function B = via_shared5();
B = A;
end
end
end
end
end
function B = via_passed1(A)
B = via_passed2(A);
end
function B = via_passed2(A)
B = via_passed3(A);
end
function B = via_passed3(A);
B = via_passed4(A);
end
function B = via_passed4(A);
B = via_passed5(A);
end
function B = via_passed5(A);
B = A;
end
end

댓글을 달려면 로그인하십시오.

추가 답변 (2개)

Jan
Jan 2021년 8월 17일
You asked clearly for the runtime of the code. Distributing a variable by evalin() is a drawback, as explained by others already. It is faster to design a program such, that all used variables are provided by input and output arguments. This is the reason, why e.g. almost all functions of Matlab's toolboxed use this method. (Exceptions: disp and save, which are driven by using the names of the variables instead of their values.)
Stephen Cobeldick hit an important point in his comment: evalin() makes the code hard to debug and to maintain. If your code is useful, you will use it in other applications. Over the time such codes will grow. In my case some tiny scripts with 20 lines of code, which fixed some inputs taken from Excel files, grow to 227'000 lines of Matlab code since 1999. Now imagine that some of the functions use variables stored in the base workspace called "A1", and the GUI of this propgram is open, while some users run scripts in the command window, which use "A1" as name of a variable by accident. This will cause unexpected outputs and it nearly impossible to debug this.
Storing variables in the base workspace and accessing them by evalin is a source of serious troubles. The debugging may need an hour, or in my case some weeks, because I would have to visit the lab, which uses my software and they will not be able to reproduce the problem until the other user runs its script again. Even if the runtime with evalin() would be some microseconds faster than with other methods, an instable code design can slow down the time to get the results dramatically.
Remember: We write code to solve problems. The time, until the problem is solved, is ths sum:
t_solved = t_designing + d_programming + t_documenting + ...
t_debugging + t_optimizing + t_runtime
Trying to improve the processing speed, while the code is still fragile dur to evalin's is called "premature optimizing" and a common reason for instable and in consequence not usable code.
Your question shows, that it is time to enter the next level of programming by learing, how to design code efficiently. Software engineering is important and more or less unknown for too many scientists. I've seen a lot of programs developped for e.g. a PhD, which are an undocumented pile of scripts which must be called in a specific order to obtain some results. As soon as the PhD is finished and the author lost the post-it on which the needed order was written, this software is useless and worth to be deleted soon.
My answer:
Do not try to improve the runtime, but spend your time to refactor the complete code, such that all variables are provided either by inputs and outputs, of by sharing the variables using inlined functions. Take into account, that good code will be reused in other projects, and this is only possible, if the functions have a well designed and documented interface. evalin() is a secure indicator for messy code, so find a way to avoid it.

Matt J
Matt J 2021년 8월 14일
You could pass 'dataset' as an input argument to your function.
  댓글 수: 4
Walter Roberson
Walter Roberson 2021년 8월 14일
In the test I just posted, I was not able to reliably determine whether shared variables or passed parameters were faster. Mathworks documents passed parameters as being faster.
When I used timeit() instead of tic/toc then the variation between runs was much greater than the difference between the timings.
Jan
Jan 2021년 8월 17일
@Walter Roberson: "When I used timeit() instead of tic/toc then the variation between runs was much greater than the difference between the timings."
This is interesting.There is a reason for the variation and for the different timings. I assume, that you did not test this with a high CPU load from other applications. According to my experiences with the undocumented JIT acceleration, both methods use a direct addressing of the variables and do not need to search in the lookup table (this is needed e.g. for eval()'ed variables). Then I'd expect more constant timings.
I'm going to run your test cases on a machine without speed-stepping of the CPU. Maybe Matlab is such efficient, that the CPU falls asleep during the processing.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by