square-accountant-83677
04/11/2023, 12:35 AMancient-application-36103
04/11/2023, 12:37 AMsquare-accountant-83677
04/11/2023, 12:37 AMsquare-accountant-83677
04/11/2023, 12:37 AMsquare-accountant-83677
04/11/2023, 12:38 AMsquare-accountant-83677
04/11/2023, 12:40 AMsquare-accountant-83677
04/11/2023, 12:47 AMdry-beach-38304
04/11/2023, 2:18 AMsquare-accountant-83677
04/11/2023, 2:19 AMsquare-accountant-83677
04/11/2023, 2:19 AMsquare-accountant-83677
04/11/2023, 2:20 AMdry-beach-38304
04/11/2023, 4:32 PM42 will be serialized and stored with foo as the key
in step B:
• 42 will again be serialized and stored with foo as the key. The difference though here is that if 42 serializes to the same thing as in A (it should in this case but it is not guaranteed) then it won’t be actually stored (uploaded) but we still have to go through the process of serializing. The reason for that is that we have absolutely no way of knowing that you didn’t modify foo in some way. Python does not allow us to make this type of assumption easily. foo could be a complex object that contains “nested” structures and you could be modifying something way deep in it. Metaflow takes a “safe” if not optimal approach and anything that you access/set is re-serialized. We do optimize, as I mentioned, and only store objects once though (it’s a content addressed store in effect).
The merge_artifacts function will not access the artifacts that are merged so it is typically faster that way. It makes the assumption (which is again not fully accurate but errors out in a “safe” way) that two objects are identical if they have the same hash (it typically errors out when two objects are the same but have DIFFERENT hashes).square-accountant-83677
04/11/2023, 4:36 PMsquare-accountant-83677
04/11/2023, 4:36 PMdry-beach-38304
04/11/2023, 4:37 PMsquare-accountant-83677
04/11/2023, 4:38 PMsquare-accountant-83677
04/11/2023, 4:38 PMdry-beach-38304
04/11/2023, 4:38 PMsquare-accountant-83677
04/11/2023, 4:40 PMdry-beach-38304
04/11/2023, 4:41 PMfrom metaflow import FlowSpec, step
class TestFlow(FlowSpec):
@step
def start(self):
self.x = 42
self.next(self.a)
@step
def a(self):
print("Reading x to be %d" % self.x)
del self.x
self.next(self.end)
@step
def end(self):
print("Reading x to be %d" % self.x)
if __name__ == "__main__":
TestFlow()
workssquare-accountant-83677
04/11/2023, 4:41 PMdry-beach-38304
04/11/2023, 4:42 PMinputs list) but it would not make it past C unless you merged it or assigned it.square-accountant-83677
04/11/2023, 4:42 PMsquare-accountant-83677
04/11/2023, 4:43 PMdry-beach-38304
04/11/2023, 4:45 PMself object if the variable is there — if it is return it and we are done, if not
• look up in the mapping — if it is there, we load from the backing storage layer (S3, etc), deserialize it and add it as an attribute to self and return it
Then, at the end of the step, we basically create the state of the datastore at the end of the step and we form it by:
• taking the datastore at the beginning (so the mapping I talked about)
• updating it with anything that is in self (so we replace anything in the mapping with stuff in self)
Crucially, when you do del self.x, you just remove stuff from self but not from the mapping so it still goes through.dry-beach-38304
04/11/2023, 4:46 PMa is the one at the beginning of end in the example code above.square-accountant-83677
04/11/2023, 4:46 PMsquare-accountant-83677
04/11/2023, 4:46 PMsquare-accountant-83677
04/11/2023, 4:46 PMdry-beach-38304
04/11/2023, 4:49 PM