2013-11-29 3 views
2

У меня есть сценарий, который может быть прерван из-за длительного времени исполнения и продолжен позже. Давайте предположим, что это выглядит как это:MATLAB: сценарий vs функция относительно вывода-аргумента

data = []; % can't preallocate as I don't know the number of entries yet here... 
while(1) 
    % ... 
    data = [data; someNewEntry]; 
end 

Хорошая вещь об этом является то, что при работе в качестве сценария, когда я прервать его, я имею в тэ рабочую переменную data.

Но я хотел преобразовать его в функцию, потому что сценарий имеет довольно большое количество переменных и помешает моей рабочей области с ней. Предположим теперь я преобразовал его так:

function data = myFnc() 
data = []; % can't preallocate as I don't know the number of entries yet here... 
while(1) 
    % ... 
    data = [data; someNewEntry]; 
end 

Проблема Nnow: Когда я прервать функцию, я теряю все записи в data, которые были сделаны до этого момента. Как решить эту проблему и вернуть текущий вектор data при прерывании функции? Единственным возможным решением я придумал, чтобы использовать что-то вроде этого, чтобы использовать в для цикла:

if(nargout == 1) 
    assignin('caller','data', data); 
end 

Но как-то мне не нравится этот подход слишком много. Но все в порядке, мне кажется. Но об этом мне все еще не нравится: при использовании этого я всегда присваиваю данные рабочей области-var data, так как я не знаю, как получить имя выходной переменной вызывающего абонента (т.е. bla = myFnc() -> это будет bla , таким образом assignin('caller','bla', data);). Я знаю, что есть функция matlab inputnames(), но я не смог найти эквивалент для выходных варов. Большое спасибо!

+1

Sidenote, если 'someNewEntry' является скаляром, например. Вы можете увеличить 'data' более эффективно, используя:' data (end + 1) = someNewEntry' –

+0

Спасибо за это, но на самом деле это вектор, создающий матрицу данных :) Но все же хорошо знать – tim

+1

В этом случае это будет «data (end + 1, :) = someNewEntry». –

ответ

1

Одним из решений может быть использование глобальных переменных. Пример с помощью простого счетчика:

function data = myFnc() 

global data; % make it a global 
if isempty(data) % not yet initialized 
    data = []; 
end 

i = 1; 
while(i < 10) 
    pause(1) 
    disp(i) 
    data = [data, i]; 
    i = i + 1; 
end 

Затем в командной строке, вы должны сделать global data один раз, и вы можете получить доступ к сохраненному состоянию. Быстрый тест, я прервала программу с CTRL + C в то время как он работает:

>> clear 
>> clear global 
>> x = myFnc(); 
    1 
    2 
    3 
    4 
Operation terminated by user during myFnc (line 10) 
>> x 
Undefined function or variable 'x'. 
>> data 
Undefined function or variable 'data'. 
>> global data 
>> data 
data = 
    1  2  3  4 

Использование глобальных переменных обычно не рекомендуется, но в некоторых случаях они могут быть полезны. Я иногда использую глобал кэшировать дорогой расчет, так что он только должен вычисляться один раз за каждый раз, когда я запускаю Matlab:

global data; 
if isempty(data) 
    data = expensive_calculation(); 
end 

Для сложных программ, есть, вероятно, более чистые способы, чтобы сохранить некоторое состояние от одной итерации к другому (реализовать некоторый объект ?, передать объект состояния с одной итерации на следующую ?, сохранить в файл?), но для некоторого быстрого и грязного сценария использование глобальных символов, вероятно, является самым простым способом.

+1

Кажется, я пропустил строку под фрагментом кода. –

+0

Единственное, о чем вы говорите: вы также пишете в var с именем 'data' вместо динамической записи в переменную, названную так, как вызывающий ее назвал :-) Это было бы неплохо. Но все равно, по крайней мере глобальная переменная данных не будет автоматически перезаписывать переменную 'data', которая уже может существовать в рабочей области (как это было бы при использовании' assignin() '). Так что это тоже довольно крутой подход :) – tim

+0

@bjoern Да, лучше дать глобальной переменной другое имя, чтобы избежать перезаписи существующей переменной. –

3

Я могу думать 2 рекомендуемых решений:

1. Прерывание функции без потери рабочего пространства

Как я описал here, это не должно быть проблемой, если вы перемещаетесь на

`dbstop if error` 

2. Часто сохраняйте переменные

С вашим решением assignin вы уже приблизились, так как он «сохраняет» переменную в базовом рабочем пространстве.Однако это все еще не очень безопасное пространство для хранения переменных. Therfore я рекомендовал бы экономить их:

save data data 

Если второй вариант слишком много убийцы производительности вы можете просто сделать это каждые 1000 итераций или около того.

+0

Я также сохраняю его в конце скрипта в файл :-) Но да, я вижу вашу точку зрения на спасение. Вы знаете способ получить имя выходной переменной вызывающего? – tim

+0

Существует функция, которая дает вам имя входной переменной вызывающего (http://www.mathworks.co.uk/help/matlab/ref/inputname.html), но я не могу найти эквивалент для выходной переменной. – am304

1

Другой вариант - использовать переменную ссылочного типа MATLAB. Например, вы могли бы использовать containers.Map, например:

m = containers.Map(); 
myFcn(m); 
% Later, after hitting CTRL-C 
m('data') % get latest value 

с функцией, как это:

function myFcn(map) 
data = []; 
while true 
    data = [data, rand()]; 
    map('data') = data; 
end 
+0

Хороший подход, спасибо за подсказку, мне тоже нравится :-) – tim

Смежные вопросы