Improve byte conversion speeds#12
Conversation
bfb3524 to
63382fe
Compare
marcelm
left a comment
There was a problem hiding this comment.
Cool! I used your benchmarking script to test another variant that uses f-strings because I recently heard they’re quite fast. So for reference, this version
def fastq_bytes(self):
return f"@{self.name}\n{self.sequence}\n+\n{self.qualities}\n".encode("ascii")
comes quite close to your improvements (your version: 0.13, f-strings: 0.15). But in this case, giving up readability is fine.
I haven’t quite finished my review, but see some comments already now.
Oh, that is interesting. I hadn't considered f-strings because these were actually slower than the original fastq_bytes implementation. But that was using pure python. I can imagine that Cython converts it automatically to some code that resembles the Python C-API calling code that I made. I think the hand-crafted code is faster because the '\n', '@' and '+' characters are not represented in a python string but are directly added in memory as a raw integer, thus saving some overhead. |
Exactly, it creates a temporary tuple, fills it one by one with the properly formatted parts of the f-string and then runs PyUnicode_Join to create the final result. |
|
@marcelm. I adressed the second review comments. |
|
Perfect, thanks, this is a nice improvement! |
|
Thanks for merging! Always a pleasure to work with you! |
|
Sorry for bothering you, but when is a new release planned? I would like fastq-filter to depend on the next version of dnaio so I can use the |
|
Doing it now |
|
Version 0.6.0 is now on PyPI |
|
Thank you for your quick response! |
Hi. Using
.encode('ascii')is a nice way to retrieve bytes, but a dedicated cython method that does the same is two times faster. This leads to noticable results on my fastq filter project:before:
After:
That is quite a substantial upgrade in runtime.
Also. I found that writing back to a file was quite slow. So I updated the fastq_bytes method. I tested several methods benchmarked them and then choose the fastest. The process can be seen in the commits.
It turns out that encoding is not necessarily slow, but Python's methods of joining strings together are. using
b"'.join([...])already decreased the runtime by 30% compared to the + methods. But I decided it was still slow and opted to do raw C-API calls and memcpy. That made it more than 3 times faster.The result is quite noticable when writing fastq files now. See below, where I benchmarked both read and read_and_write. The write speed is the difference between the two.
Before:
All records are written in about 2.2 seconds.
After
All records are written in about 1.3 seconds.
That is quite a good improvement.