问题
I consult "Handle Classes" section of
http://uk.mathworks.com/help/distcomp/objects-and-handles-in-parfor-loops.html
and write this:
parfor j = 1:length(stores)
store = stores(j);
dataj = somefunction(store.someproperty, data(data.store == store.id, :));
stores(j) = store.dosomething(dataj);
end
where dosomething modifies store's state. (store is a handle class).
The loop works fine with for; switch to parfor, and store object's state fails to be updated.
Is this a problem with Matlab's doc, or with my understanding of it?
UPD. Editing comments is a pain, so I continue here. Here's a toy class, with two methods, modifying the object's state.
classdef shop < handle
properties
stock = 10
end
methods
function clearstock(obj)
obj.stock = 0;
end
function[obj] = clearstock2(obj)
obj.stock = 0;
end
end
end
Now the test script:
n = 1;
shops = repmat(shop, n, 1);
sprintf('Stock before: %d', shops(1).stock)
% A
parfor i = 1:n
shops(i).clearstock;
end
sprintf('Stock after: %d', shops(1).stock)
% B
shops = repmat(shop, n, 1);
parfor i = 1:n
shops(i).clearstock2;
end
sprintf('Stock after: %d', shops(1).stock)
% C
shops = repmat(shop, n, 1);
parfor i = 1:n
shop = shops(i);
shop.clearstock;
shops(i) = shop;
end
sprintf('Stock after: %d', shops(1).stock)
% D
shops = repmat(shop, n, 1);
parfor i = 1:n
shop = shops(i);
shop = shop.clearstock2;
shops(i) = shop;
end
sprintf('Stock after: %d', shops(1).stock)
(A,B) leave the state unchanged, (C,D) work as intended/advertised. Now, my 'real', 'non-toy' objects' state is a mix of built-in and custom classes. (The state element that is not being updated is a cell array of numeric arrays). Are the latter to blame, I wonder?
UPD2. A user-defined handle class as a property - still working as expected.
%MANAGER.M
classdef manager < handle
properties
name
salary = 100000;
end
methods
function[obj] = manager(name)
obj.name = name;
end
function giveraise(obj)
obj.salary = 200000;
end
function[obj] = giveraise2(obj)
obj.salary = 300000;
end
end
end
%SHOP.M
classdef shop < handle
properties
stock = 10;
manager = manager('John Doe');
end
methods
function clearstock(obj)
obj.stock = 0;
end
function[obj] = clearstock2(obj)
obj.stock = 0;
end
end
end
clc
n = 1;
shops = repmat(shop, n, 1);
sprintf('Stock before: %d', shops(1).stock)
sprintf('Salary before: %d', shops(1).manager.salary)
% A2
parfor i = 1:n
shops(i).clearstock;
shops(i).manager.giveraise;
end
sprintf('Stock after: %d', shops(1).stock)
sprintf('Salary after: %d', shops(1).manager.salary)
% B2
shops = repmat(shop, n, 1);
parfor i = 1:n
shop = shops(i);
shop.clearstock;
shop.manager.giveraise;
shops(i) = shop;
end
sprintf('Stock after: %d', shops(1).stock)
sprintf('Salary after: %d', shops(1).manager.salary)
% C2
shops = repmat(shop, n, 1);
parfor i = 1:n
shop = shops(i);
shop.manager = shop.manager.giveraise2;
shop = shop.clearstock2;
shops(i) = shop;
end
sprintf('Stock after: %d', shops(1).stock)
sprintf('Salary after: %d', shops(1).manager.salary)
Is it about value classes, then?
UPD3. No, a user-defined value class for shop property worked fine. I stop until I can come up with a reproducible example.
回答1:
It's a bit tricky since we don't see the whole code, but my best guess is that dosomething method does not return the modified store object instance, and returns something else instead. When you run it with the usual for loop, this method actually changes store handle object. When you run it with parfor, however, the only thing that gets persisted outside the loop is the return value of dosomething that is assigned to stores(j). Please try the following instead:
parfor j = 1:length(stores)
store = stores(j);
dataj = somefunction(store.someproperty, data(data.store == store.id, :));
store.dosomething(dataj);
stores(j) = store;
end
As an alternative, make sure dosomething returns the object itself, i.e.
function obj = dosomething(obj, dataj)
% ...
end
回答2:
Problem solved, and it lay outside of the presented code.
The parfor loop was inside a function, simulateoneday, which was called, in a loop, from function simulatemultipledays. simulatemultipledays would pass to simulateoneday an array of store objects, which would then go to parfor.
It wasn't parfor that was 'resetting' objects' state - instead, it was the simulatemultipledays-to-simulateoneday passage. When I 'absorbed' simulateoneday into simulatemultipledays, things started working.
I wondered if I had tripped up on pass-by-value-vs.-pass-by-reference, but hey, the code worked fine with for - it was parfor which broke things.
来源:https://stackoverflow.com/questions/35976395/handle-classes-with-matlab-parfor-loops