-
Notifications
You must be signed in to change notification settings - Fork 947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle buffers in Widget._should_send_property
#1595
Changes from 1 commit
6445ea9
afe6ae6
40cd07c
349f556
db04817
4d912e4
7d56205
b9eb8c8
0f0761c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -483,7 +483,7 @@ def _compare(self, a, b): | |
else: | ||
return a == b | ||
|
||
def _compare_buffers(self, a, b, key): | ||
def _buffer_list_equal(self, a, b): | ||
"""Compare two lists of buffers for equality. | ||
|
||
Used to decide whether two sequences of buffers (memoryviews) differ, | ||
|
@@ -501,7 +501,9 @@ def _compare_buffers(self, a, b, key): | |
# e.g. memoryview(np.frombuffer(ia, dtype='float32')) != | ||
# memoryview(np.frombuffer(b)), since the format info differs. | ||
# However, since we only transfer bytes, we use `tobytes()`. | ||
if ia.tobytes() != ib.tobytes(): | ||
iabytes = ia.tobytes() if isinstance(ia, memoryview) else ia | ||
ibbytes = ib.tobytes() if isinstance(ib, memoryview) else ib | ||
if ia != ib: | ||
return False | ||
return True | ||
|
||
|
@@ -620,13 +622,14 @@ def _should_send_property(self, key, value): | |
# idiosyncracies of how python data structures map to json, for example | ||
# tuples get converted to lists. | ||
if key in self._property_lock: | ||
# model_state, buffer_paths, buffers | ||
split_value = _remove_buffers({ key: to_json(value, self)}) | ||
split_lock = _remove_buffers({ key: self._property_lock[key]}) | ||
# Compare state and buffer_paths | ||
if jsondumps(split_value[:2]) == jsondumps(split_lock[:2]): | ||
# Compare buffers | ||
if self._compare_buffers(split_value[2], split_lock[2], key): | ||
return False | ||
if (jsonloads(jsondumps(split_value[0])) == jsonloads(jsondumps(split_lock[0])) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rather pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. I also factored out this comparison into a top-level function. |
||
and split_value[1] == split_lock[1] | ||
and self._buffer_list_equal(split_value[2], split_lock[2])): | ||
return False | ||
if self._holding_sync: | ||
self._states_to_send.add(key) | ||
return False | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have this as an extension point, keeping the key could be very informative as to which kind of comparison to perform. If anything, it's a problem with the current
_compare
that it does not have it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g. for certain keys you might want to do a floating point comparison with a given precision, while for another you need exact equality. Without the key, you will not be able to determine which comparison to apply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate on this being an extension point? I don't understand how you're thinking of this as an extension point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean extension point as in "something an inheriting class might want to override".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this comparison depends on the top-level put/remove buffer function implementations, so I factored out the comparison to also be a top-level function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Since it depends on the implementation of the top-level functions (i.e., what exactly can be in the buffers list), I think it makes more sense to not override it, and instead put it at the top level too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation works for me, but if someone uses a serializer/deserialize set that might introduce noise when data is passed through a loop (
a != serializer(deserialize(a))
), e.g. floating point inaccuracies, they will want to override this comparison.It is still possible to do that by overriding the
_should_send_property
function, but it will be more brittle as it needs to take into account the internals of that method (e.g._property_lock
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I might be over-engineering this one. Other fields in the state other than buffers might also have this issue, so there is no obvious reason to give buffers preferential treatment.