问题
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