Moje pytanie jest bardzo specyficzne dla wątków kompilatora i środowiska wykonawczego matlab. Ponieważ tylko osoby znające API środowiska wykonawczego matlab mogą odpowiedzieć, znacznie skróciłem szczegóły. Daj mi znać, jeśli mam być bardziej szczegółowy.Matlab: Jak badać skompilowany postęp m-code z zewnętrznego API?
Wprowadzenie
Korzystanie MATLAB kompilatora & czas pracy mogę wywołać funkcję napisane w m-kodu z programu C#. Powiedzmy, nazywając:
function [result] = foo(n)
%[
result = 0;
for k = 1:n,
pause(1.0); % simulate long processing
result = result + 42;
end
%]
z (gdzieś za kilka dllimports w kodzie C#):
mclFeval(IntPtr inst, string name, IntPtr[] plhs, IntPtr[] prhs)
Tak daleko, tak dobrze, nie mam problemu z tym (tj intializing runtime, ładowanie '.cft' file, zestawiania iz powrotem MxArray z Net typów, etc ...)
Mój problem
chciałbym przyjrzeć się postępowi moim foo
funkcji u śpiewać jakieś cancel
i progress
zwrotnych:
function [result] = foo(n, cancelCB, progressCB)
%[
if (nargin < 3), progressCB = @(ratio, msg) disp(sprintf('Ratio = %f, Msg = %s', ratio, msg)); end
if (nargin < 2), cancelCB = @() disp('Checking cancel...'); end
result = 0;
for k = 1:n,
if (~isempty(cancelCB)),
cancelCB(); % Up to the callback to raise some error('cancel');
end;
if (~isempty(progressCB)),
progressCB(k/n, sprintf('Processing (%i/%i)', k, n));
end
pause(1.0); % simulate long processing
result = result + 42;
end
%]
Ale oczywiście chciałbym te wywołania zwrotne, aby być w kodzie C#, a nie w m-jeden.
Badania
Patrząc na nagłówku pliku „mclmcr.h”, wygląda jak te funkcje mogą być pomocne:
extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn); extern bool mclRegisterExternalFunction(HMCRINSTANCE inst, const char* varname, mxFunctionPtr fcn);
Niestety są one całkowicie nieudokumentowane i nie znalazłem przypadek użycia Mógłbym naśladować, aby zrozumieć, jak działają.
Ja również myślał o tworzeniu COM widocznego obiektu w C# i przekazać go jako parametr do kodu Matlab:
// Somewhere within C# code: var survey = new ComSurvey(); survey.SetCancelCallback = () => { if (/**/) throw new OperationCancelException(); }; survey.SetProgressCallback = (ratio, msg) => { /* do something */ };
function [result] = foo(n, survey) %[ if (nargin < 2), survey = []; end result = 0; for k = 1:n, if (~isempty(survey)), survey.CheckCancel(); % up to the COM object to raise exception survey.SetProgress(k/n, sprintf('Processing... %i/%i', k, n)); end pause(1.0); % simulate long processing result = result + 42; end %]
jestem bardzo obeznany z funkcje do tworzenia tablic numerycznych i struktury oraz ich stosowania:
extern mxArray *mxCreateNumericArray(...) extern mxArray *mxCreateStructArray(...)
W każdym razie, jak obiekty COM są pakowane do MxArrays, nie wiem?
Dalsze badania
Dzień + 1
Nawet jeśli nadal niestabilna, udało mi się mieć Matlab do callback do mojego kodu C# i wydaje się, że mclCreateSimpleFunctionHandle
jest kierunek iść.
Uwaga: Poniższy kod służy wyłącznie jako odniesienie. Może nie być odpowiedni w twoim własnym kontekście, jaki jest. Dostarczę prostszy kod później (tj. Gdy dostanę stabilne rozwiązanie).
Patrząc podpisania
mxFunctionPtr
, stworzyłem dwóch delegatów tak:// Mimic low level signature for a Matlab function pointer [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] delegate void MCRInteropDelegate(int nlhs, IntPtr[] plhs, int nrhs, IntPtr[] prhs);
i
// Same signature (but far more elegant from .NET perspective) delegate void MCRDelegate(MxArray[] varargouts, MxArray[] varargins);
ja również związane z wykonywania tak:
[DllImport("mclmcrrt74.dll", EntryPoint = "mclCreateSimpleFunctionHandle", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)] static extern IntPtr _mclCreateSimpleFunctionHandle(MCRInteropDelegate fctn);
Zakładając
MxArray
jest klasą .NET z kopalni, które po prostu hermetyzacji dlamxArray*
uchwytami, ja wtedy marshaled moje delegatów tak:// Create MxArray from corresponding .NET delegate static MxArray CreateFromDelegate(MCRDelegate del) { // Package high level delegate signature to a 'dllimport' signature MCRInteropDelegate interopDel = (nlhs, plhs, nrhs, prhs) => { int k = 0; var varargouts = new MxArray[nlhs]; var varargins = new MxArray[nrhs]; // (nrhs, prhs) => MxArray[] varargins Array.ForEach(varargins, x => new MxArray(prhs[k++], false)); // false = is to indicate that MxArray must not be disposed on .NET side // Call delegate del(varargouts, varargins); // Todo: varargouts created by the delegate must be destroyed by matlab, not by .NET !! // MxArray[] varargouts => (nlhs, plhs) k = 0; Array.ForEach(plhs, x => varargouts[k++].getPointer()); }; // Create the 1x1 array of 'function pointer' type return new MxArray(MCRInterop.mclCreateSimpleFunctionHandle(interopDel)); }
Wreszcie, zakładając
module
jest instancjąMCRModule
(ponownie, klasa mine do hermetyzacjihInst*
na niskim poziomiemclFeval
API), udało mi się zadzwonićfoo
funkcję i mieć to, aby wprowadzić moją .NETcancel
delegat tak:// Create cancel callback in .NET MCRDelegate cancel = (varargouts, varargins) => { if ((varargouts != null) && (varargouts.Length != 0) { throw new ArgumentException("'cancel' callback called with too many output arguments"); } if ((varargins != null) && (varargins.Length != 0) { throw new ArgumentException("'cancel' callback called with too many input arguments"); } if (...mustCancel...) { throw new OperationCanceledException(); } } // Enter the m-code // NB: Below function automatically converts its parameters to MxArray // and then call low level mclFeval with correct 'mxArray*' handles module.Evaluate("foo", (double)10, cancel);
Ten kod .NET działał bez zarzutu, a
foo
rzeczywiście poprawnie wykonał oddzwanianie do delegatacancel
.Jedynym problemem jest to, że jest dość niestabilny. Domyślam się, że użyłem zbyt wielu anonimowych funkcji i prawdopodobnie niektóre z nich są zbyt wcześnie ...
Czy spróbuję dostarczyć stabilne rozwiązanie w ciągu kilku następnych dni? (mam nadzieję, że dzięki prostszemu kodowi do odczytu i kopiowania - wklej w swoim własnym kontekście do natychmiastowego przetestowania).
Proszę dać mi znać, jeśli myślisz, że idę w złym kierunku z
mclCreateSimpleFunctionHandle
.
Czy za naiwne podejście łamanie działania na małe kawałki i uruchomić je w pętli w C#? –
Tak, ale o tym (również w celu dostarczenia przykładowej aplikacji tutaj bez całego kodu za dodałem do pracy z MCR). Prawdopodobnie wrócę do tej kwestii na początku przyszłego roku, bo teraz jestem zbyt zapisany do innych niezwiązanych problemów (WPF). – CitizenInsane
OK, @CitizenInsane, proszę zaktualizować ten post, jeśli możesz, naprawdę potrzebuję tego! –