Skip to content
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

add ZStandard compression #45

Merged
merged 2 commits into from
Apr 25, 2024
Merged

Conversation

redorff
Copy link
Contributor

@redorff redorff commented Apr 25, 2024

No description provided.

@alexprengere
Copy link
Collaborator

Looks great!
Any reason why pyzstd was chosen over zstandard?
httpx landed the equivalent feature a few weeks ago and went with zstandard.

@redorff
Copy link
Contributor Author

redorff commented Apr 25, 2024

I got a little scared by their multiple warnings about thread safety...

Unless stated otherwise, ZstdCompressor and ZstdDecompressor instances cannot be used for temporally overlapping (de)compression operations. i.e. if you start a (de)compression operation on an instance or a helper object derived from it, it isn’t safe to start another (de)compression operation from the same instance until the first one has finished.
ZstdCompressor and ZstdDecompressor instances have no guarantees about thread safety. Do not operate on the same ZstdCompressor and ZstdDecompressor instance simultaneously from different threads. It is fine to have different threads call into a single instance, just not at the same time.

and as you probably want to have multiple thread on your webserver...

pyzstd is not warning about potential thread issues... but I admit it does not imply that there are no such issues...

@alexprengere
Copy link
Collaborator

AFAICT, regarding the warning:

if you start a (de)compression operation on an instance or a helper object derived from it, it isn't safe to start another (de)compression operation from the same instance until the first one has finished.

Even if flask-compress is used in a threaded context, only a single thread will ever process a single response, so as long as the ZstdDecompressor object is not shared across threads, it should be fine. A similar pattern is used for gzip decompression.

So in a nutshell, looking at the compress function relevant part:

 elif algorithm == 'zstd':
     # The zstandard.ZstdCompressor() should be created here, so it is not shared

For context, there is relevant information regarding the various zstd implementations here.

@redorff
Copy link
Contributor Author

redorff commented Apr 25, 2024

Yes. Ok.

Reusing a ZstdCompressor or ZstdDecompressor instance for multiple operations is faster than instantiating a new ZstdCompressor or ZstdDecompressor for each operation.

Would it also work to store the object once for good in self ?

elif algorithm == 'zstd':
    if self.zstd is None:
        self.zstd = zstandard.ZstdCompressor(level=app.config['COMPRESS_ZSTD_LEVEL'])
    return self.zstd.compress(response.get_data())

@alexprengere
Copy link
Collaborator

As the Compress object is global to the process (in most cases), I think this is what the warning is warning about 😉.
Flask-compress code code could add thread locking to prevent race conditions, but I would rather have a first version that is "obviously correct", then if this turns out to be slow we can look into further optimizations, like carefully re-using ZstdCompressor objects.

I did some tests on my not-so-recent hardware, and I measure the creation time of ZstdCompressor() to be around 900ns, which is not super-fast, but in the context of a HTTP webserver, I think sub-ms overhead is reasonable.

@redorff
Copy link
Contributor Author

redorff commented Apr 25, 2024

Ok. I'll fix it as you suggested then.
Do you know how to get rid of the failing test https://results.pre-commit.ci/run/github/142751498/1714036047.24xoLujVSeeGm64hBfSY7w ?

@alexprengere
Copy link
Collaborator

This pre-commit check is not part of the workflow file, so I think this must be something enabled at org level. @KelSolaar @MichaelMauderer perhaps you may help (I pinged you as I think you have the admin rights)

@alexprengere alexprengere merged commit a493830 into colour-science:master Apr 25, 2024
12 of 13 checks passed
@alexprengere
Copy link
Collaborator

Thanks a lot! I will release soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants