| 58 | self.chunk_size = chunk_size |
| 59 | |
| 60 | async def _async_generator(self): |
| 61 | # Generators don't actually start running until the first time you call |
| 62 | # next() on them, so make the generator object in the async thread and |
| 63 | # then repeatedly dispatch to it in a sync thread. |
| 64 | sync_generator = self.__iter__() |
| 65 | |
| 66 | def next_slice(gen): |
| 67 | return list(islice(gen, self.chunk_size)) |
| 68 | |
| 69 | while True: |
| 70 | chunk = await sync_to_async(next_slice)(sync_generator) |
| 71 | for item in chunk: |
| 72 | yield item |
| 73 | if len(chunk) < self.chunk_size: |
| 74 | break |
| 75 | |
| 76 | # __aiter__() is a *synchronous* method that has to then return an |
| 77 | # *asynchronous* iterator/generator. Thus, nest an async generator inside |