Repository navigation
Separate query and S3 read worker settings #1103
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
Changes from all commits
dda6aae
d30dff2
8f1d1af
c120e30
f316843
0233108
9df509e
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 |
|---|---|---|
|
|
@@ -46,6 +46,29 @@ A cursor subclass that receives settings of its own must not pass them on to the | |
| The pandas and Polars cursors pass the `execute()` keyword arguments that they do not use themselves to the reader, such as `pandas.read_csv()`. | ||
| The reader rejects an unknown name when it reads the query results, which PyAthena raises as `OperationalError`; the name is not checked when there are no results to read. | ||
|
|
||
| ## Worker settings in PyAthena 4.0 | ||
|
|
||
| The pandas and Polars cursors take the number of threads that read each result file from S3 as `s3_max_workers`. | ||
| It can be set in the cursor constructor and overridden for one query in `execute()`. | ||
| The default is `(cpu_count() or 1) * 5`. | ||
| Polars uses it only for CSV results read without `chunksize`. | ||
| Chunked CSV reads and UNLOAD results use Polars' native readers, which do not use this setting. | ||
|
|
||
| The thread-pool cursors, such as `AsyncCursor`, `AsyncPandasCursor`, and `AsyncPolarsCursor`, keep `max_workers` for the size of the thread pool that waits for queries and collects their results. | ||
|
|
||
| ```python | ||
| from pyathena.pandas.async_cursor import AsyncPandasCursor | ||
|
|
||
| cursor = connection.cursor(AsyncPandasCursor, max_workers=4, s3_max_workers=2) | ||
| query_id, future = cursor.execute("SELECT 1", s3_max_workers=3) | ||
| ``` | ||
|
|
||
| Before PyAthena 4.0, `max_workers` set the S3 read workers of `PandasCursor`, `PolarsCursor`, `AioPandasCursor`, and `AioPolarsCursor`, and of `execute()` in the pandas and Polars cursors. | ||
|
Member
Author
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. Self-review round two after scope reduction — CLEAN after the PR-body correction recorded in round one. Base: Claims checked: (1) Correction left in history: commit Limits: docs example and AWS paths are not run locally;
Member
Author
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. Round-two follow-up for the documentation repair — CLEAN. Old head
Member
Author
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. Final runtime validation: head
Member
Author
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. Round-two follow-up after merging master — CLEAN. Claims: (1) "Passing
Member
Author
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. Final runtime validation after the master merge: head |
||
| Replace it with `s3_max_workers` in those places. | ||
| Passing `max_workers` to those four constructors raises `TypeError`. | ||
|
Member
Author
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. Relayed independent static follow-up for the master merge — FINDINGS (one Low doc wording), repaired; follow-up CLEAN. Reviewer: Codex CLI 0.161.0, model |
||
| Passing it to `execute()` raises `TypeError` after the query has run; with `AsyncPandasCursor` and `AsyncPolarsCursor`, the returned future raises it. | ||
| `AsyncPolarsCursor` used its `max_workers` for both the thread pool and the S3 read workers; pass both arguments to keep the former values. | ||
|
|
||
| ## Managed query result storage | ||
|
|
||
| When using a workgroup with [managed query result storage](https://docs.aws.amazon.com/athena/latest/ug/managed-results.html) enabled, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -78,6 +78,7 @@ def __init__( | |
| block_size: int | None = None, | ||
| cache_type: str | None = None, | ||
| chunksize: int | None = None, | ||
| s3_max_workers: int = (cpu_count() or 1) * 5, | ||
| **kwargs, | ||
| ) -> None: | ||
| """Initialize an AsyncPolarsCursor. | ||
|
|
@@ -91,7 +92,7 @@ def __init__( | |
| encryption_option: S3 encryption option (SSE_S3, SSE_KMS, CSE_KMS). | ||
| kms_key: KMS key ARN for encryption. | ||
| kill_on_interrupt: Cancel running query on keyboard interrupt. | ||
| max_workers: Maximum number of workers for concurrent execution. | ||
| max_workers: Size of the cursor thread pool for waiting and collecting results. | ||
| arraysize: Number of rows to fetch per batch. | ||
| unload: Enable UNLOAD for high-performance Parquet output. | ||
| result_reuse_enable: Enable Athena query result reuse. | ||
|
|
@@ -101,6 +102,7 @@ def __init__( | |
| chunksize: Number of rows per chunk for memory-efficient processing. | ||
| If specified, data is loaded lazily in chunks for all data | ||
| access methods including fetchone(), fetchmany(), and iter_chunks(). | ||
| s3_max_workers: Maximum worker threads per S3 file reader. | ||
| **kwargs: Additional connection parameters. | ||
|
|
||
| Example: | ||
|
|
@@ -123,6 +125,7 @@ def __init__( | |
| result_reuse_minutes=result_reuse_minutes, | ||
| **kwargs, | ||
| ) | ||
| self._s3_max_workers = s3_max_workers | ||
| self._unload = unload | ||
| self._block_size = block_size | ||
| self._cache_type = cache_type | ||
|
|
@@ -186,7 +189,7 @@ def _collect_result_set( | |
| unload_location=unload_location, | ||
| block_size=kwargs.pop("block_size", self._block_size), | ||
| cache_type=kwargs.pop("cache_type", self._cache_type), | ||
| max_workers=kwargs.pop("max_workers", self._max_workers), | ||
| max_workers=kwargs.pop("s3_max_workers", self._s3_max_workers), | ||
|
Member
Author
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. Self-review round one after scope reduction — FINDINGS (one claim correction, no code repair). Base: Covered: constructor and Finding (fixed in the PR body): the body said a former Evidence:
Member
Author
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. Round-one follow-up for the independent documentation finding — CLEAN. Old head
Member
Author
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. Round-one follow-up after merging master — CLEAN after one documentation repair. The merge conflicted only in docs/usage.md (#1102's unknown-keyword paragraph and this PR's worker section), resolved by keeping both. Code merged without conflicts. Checked upstream contracts touching the rename: |
||
| chunksize=kwargs.pop("chunksize", self._chunksize), | ||
| result_set_type_hints=result_set_type_hints, | ||
| **kwargs, | ||
|
|
@@ -231,7 +234,7 @@ def execute( | |
| :class:`~pyathena.options.ExecuteOptions` instance. Individual | ||
| keyword arguments take precedence over ``options`` fields. | ||
| **kwargs: Additional execution parameters passed to Polars read functions. | ||
| ``block_size``, ``cache_type``, ``max_workers``, and ``chunksize`` | ||
| ``block_size``, ``cache_type``, ``s3_max_workers``, and ``chunksize`` | ||
| override the cursor's values for this query. | ||
| Read function arguments replace the ones the result set chooses, such as | ||
| ``separator``, ``has_header``, ``schema_overrides``, and ``storage_options`` | ||
|
|
||
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.
Relayed independent static review — FINDINGS (one Low documentation finding), repaired; follow-up CLEAN.
Reviewer: Codex CLI 0.161.0, model
gpt-6.1-sol(a different model from the Claude author of this revision),codex exec -s read-onlyin a detached clean snapshot. No edits, builds, tests, network, or GitHub access; the prompt omitted the PR number, body, commits, and prior findings.Initial review — session
01a1216d-29c9-7751-a8c5-e1630b9bb34f, basef3532e9fb57fd769441e533f0b8375fd854ece69, headc120e3011a9d20dbf8f12e27765df0794da39973. Covered all six pandas/Polars cursors (constructor settings, defaults, routing, per-query overrides), thread-pool independence, unchanged result-set/filesystem names and Arrow docstring, all repository callers (benchmarks, tests, docs, README, connection factories, sync/async SQLAlchemy dialects), regression coverage, docstrings, and simplicity. No implementation defect; it noted the tests use mocked result sets and do not test overlapping overrides.Finding (P3): docs/usage.md said only UNLOAD bypasses
s3_max_workersfor Polars, but chunked CSV reads also do —pyathena/polars/result_set.py:778passes_parquet_storage_options(native object_store, no worker value) topl.scan_csv. Verified by the author.An earlier delegated Codex run (thread
01a1216c-1a5d-7d02-8b74-810ca7993e7f) ended with a placeholder message and no review; it is not counted.Repair
f316843f84e1dc839e1dd243e1ca3fa76b188c18: the docs now say Polars uses the setting only for CSV results read withoutchunksize, and chunked CSV and UNLOAD reads use Polars' native readers.Follow-up — session
01a12170-fac9-7bb0-88a7-61d533338321, diffc120e3011a9d20dbf8f12e27765df0794da39973..f316843f84e1dc839e1dd243e1ca3fa76b188c18: CLEAN. Verified non-chunked CSV, chunked CSV, non-chunked and chunked UNLOAD Parquet, and results without an output file; userstorage_optionsreplace the defaults, so "only for" is not overstated. The review snapshot remained clean. Static review only.