Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/howto/free-threading-python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ optionally support installing free-threaded Python binaries. The installers
are available at https://www.python.org/downloads/.

For information on other platforms, see the `Installing a Free-Threaded Python
<https://py-free-threading.github.io/installing_cpython/>`_, a
<https://py-free-threading.github.io/installing-cpython/>`_, a
community-maintained installation guide for installing free-threaded Python.

When building CPython from source, the :option:`--disable-gil` configure option
Expand Down
25 changes: 23 additions & 2 deletions Doc/library/asyncio-eventloop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ Creating Futures and Tasks

.. versionadded:: 3.5.2

.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=None)
.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)

Schedule the execution of :ref:`coroutine <coroutine>` *coro*.
Return a :class:`Task` object.
Expand All @@ -370,6 +370,10 @@ Creating Futures and Tasks
for interoperability. In this case, the result type is a subclass
of :class:`Task`.

The full function signature is largely the same as that of the
:class:`Task` constructor (or factory) - all of the keyword arguments to
this function are passed through to that interface.

If the *name* argument is provided and not ``None``, it is set as
the name of the task using :meth:`Task.set_name`.

Expand All @@ -388,8 +392,15 @@ Creating Futures and Tasks
.. versionchanged:: 3.11
Added the *context* parameter.

.. versionchanged:: 3.13.3
Added ``kwargs`` which passes on arbitrary extra parameters, including ``name`` and ``context``.

.. versionchanged:: 3.13.4
Rolled back the change that passes on *name* and *context* (if it is None),
while still passing on other arbitrary keyword arguments (to avoid breaking backwards compatibility with 3.13.3).

.. versionchanged:: 3.14
Added the *eager_start* parameter.
All *kwargs* are now passed on. The *eager_start* parameter works with eager task factories.

.. method:: loop.set_task_factory(factory)

Expand All @@ -402,6 +413,16 @@ Creating Futures and Tasks
event loop, and *coro* is a coroutine object. The callable
must pass on all *kwargs*, and return a :class:`asyncio.Task`-compatible object.

.. versionchanged:: 3.13.3
Required that all *kwargs* are passed on to :class:`asyncio.Task`.

.. versionchanged:: 3.13.4
*name* is no longer passed to task factories. *context* is no longer passed
to task factories if it is ``None``.

.. versionchanged:: 3.14
*name* and *context* are now unconditionally passed on to task factories again.

.. method:: loop.get_task_factory()

Return a task factory or ``None`` if the default one is in use.
Expand Down
21 changes: 17 additions & 4 deletions Doc/library/asyncio-task.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,18 +238,24 @@ Creating Tasks

-----------------------------------------------

.. function:: create_task(coro, *, name=None, context=None)
.. function:: create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)

Wrap the *coro* :ref:`coroutine <coroutine>` into a :class:`Task`
and schedule its execution. Return the Task object.

If *name* is not ``None``, it is set as the name of the task using
:meth:`Task.set_name`.
The full function signature is largely the same as that of the
:class:`Task` constructor (or factory) - all of the keyword arguments to
this function are passed through to that interface.

An optional keyword-only *context* argument allows specifying a
custom :class:`contextvars.Context` for the *coro* to run in.
The current context copy is created when no *context* is provided.

An optional keyword-only *eager_start* argument allows specifying
if the task should execute eagerly during the call to create_task,
or be scheduled later. If *eager_start* is not passed the mode set
by :meth:`loop.set_task_factory` will be used.

The task is executed in the loop returned by :func:`get_running_loop`,
:exc:`RuntimeError` is raised if there is no running loop in
current thread.
Expand Down Expand Up @@ -290,6 +296,9 @@ Creating Tasks
.. versionchanged:: 3.11
Added the *context* parameter.

.. versionchanged:: 3.14
Added the *eager_start* parameter by passing on all *kwargs*.


Task Cancellation
=================
Expand Down Expand Up @@ -330,7 +339,7 @@ and reliable way to wait for all tasks in the group to finish.

.. versionadded:: 3.11

.. method:: create_task(coro, *, name=None, context=None)
.. method:: create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)

Create a task in this task group.
The signature matches that of :func:`asyncio.create_task`.
Expand All @@ -342,6 +351,10 @@ and reliable way to wait for all tasks in the group to finish.

Close the given coroutine if the task group is not active.

.. versionchanged:: 3.14

Passes on all *kwargs* to :meth:`loop.create_task`

Example::

async def main():
Expand Down
56 changes: 53 additions & 3 deletions Lib/test/test_zstd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2430,10 +2430,8 @@ def test_buffer_protocol(self):
self.assertEqual(f.write(arr), LENGTH)
self.assertEqual(f.tell(), LENGTH)

@unittest.skip("it fails for now, see gh-133885")
class FreeThreadingMethodTests(unittest.TestCase):

@unittest.skipUnless(Py_GIL_DISABLED, 'this test can only possibly fail with GIL disabled')
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_compress_locking(self):
Expand Down Expand Up @@ -2470,7 +2468,6 @@ def run_method(method, input_data, output_data):
actual = b''.join(output) + rest2
self.assertEqual(expected, actual)

@unittest.skipUnless(Py_GIL_DISABLED, 'this test can only possibly fail with GIL disabled')
@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_decompress_locking(self):
Expand Down Expand Up @@ -2506,6 +2503,59 @@ def run_method(method, input_data, output_data):
actual = b''.join(output)
self.assertEqual(expected, actual)

@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_compress_shared_dict(self):
num_threads = 8

def run_method(b):
level = threading.get_ident() % 4
# sync threads to increase chance of contention on
# capsule storing dictionary levels
b.wait()
ZstdCompressor(level=level,
zstd_dict=TRAINED_DICT.as_digested_dict)
b.wait()
ZstdCompressor(level=level,
zstd_dict=TRAINED_DICT.as_undigested_dict)
b.wait()
ZstdCompressor(level=level,
zstd_dict=TRAINED_DICT.as_prefix)
threads = []

b = threading.Barrier(num_threads)
for i in range(num_threads):
thread = threading.Thread(target=run_method, args=(b,))

threads.append(thread)

with threading_helper.start_threads(threads):
pass

@threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_decompress_shared_dict(self):
num_threads = 8

def run_method(b):
# sync threads to increase chance of contention on
# decompression dictionary
b.wait()
ZstdDecompressor(zstd_dict=TRAINED_DICT.as_digested_dict)
b.wait()
ZstdDecompressor(zstd_dict=TRAINED_DICT.as_undigested_dict)
b.wait()
ZstdDecompressor(zstd_dict=TRAINED_DICT.as_prefix)
threads = []

b = threading.Barrier(num_threads)
for i in range(num_threads):
thread = threading.Thread(target=run_method, args=(b,))

threads.append(thread)

with threading_helper.start_threads(threads):
pass


if __name__ == "__main__":
Expand Down
11 changes: 2 additions & 9 deletions Modules/_zstd/clinic/decompressor.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 4 additions & 23 deletions Modules/_zstd/clinic/zstddict.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading