Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gevent
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gevent
Commits
e7f64dc2
Commit
e7f64dc2
authored
Jul 14, 2015
by
Jason Madden
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ThreadPool applies immediately when called from a worker thread to avoid LoopExit. Fixes #131.
parent
2d9e5a62
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
51 additions
and
8 deletions
+51
-8
changelog.rst
changelog.rst
+5
-0
doc/gevent.threadpool.rst
doc/gevent.threadpool.rst
+11
-4
gevent/hub.py
gevent/hub.py
+1
-1
gevent/pool.py
gevent/pool.py
+11
-1
gevent/threadpool.py
gevent/threadpool.py
+6
-2
greentest/test__threadpool.py
greentest/test__threadpool.py
+17
-0
No files found.
changelog.rst
View file @
e7f64dc2
...
...
@@ -60,6 +60,11 @@ Unreleased
if asked to run something that cannot be run. Previously, the
spawned greenlet would die with an uncaught ``TypeError`` the first
time it was switched to. Reported in :issue:`119` by stephan.
- Recursive use of ``gevent.threadpool.ThreadPool.apply`` no longer
raises a ``LoopExit`` error (using ``ThreadPool.spawn`` and then
``get`` on the result still could; you must be careful to use the
correct hub). Reported in :issue:`131` by 8mayday.
1.1a2 (Jul 8, 2015)
===================
...
...
doc/gevent.threadpool.rst
View file @
e7f64dc2
...
...
@@ -10,10 +10,17 @@
.. method:: apply(func, args=None, kwds=None)
Rough equivalent of the :func:`apply
` builtin, blocking until
the result is ready and returning it.
Rough equivalent of the :func:`apply
()` builtin function,
blocking until
the result is ready and returning it.
.. warning:: As implemented, attempting to use
The ``func`` will *usually*, but not *always*, be run in a way
that allows the current greenlet to switch out (for example,
in a new greenlet or thread, depending on implementation). But
if the current greenlet or thread is already one that was
spawned by this pool, the pool may choose to immediately run
the `func` synchronously.
.. note:: As implemented, attempting to use
:meth:`Threadpool.appy` from inside another function that
was itself spawned in a threadpool (any threadpool) will
lead to the hub throwing LoopExit
.
cause the function to be run immediatesly
.
gevent/hub.py
View file @
e7f64dc2
...
...
@@ -475,7 +475,7 @@ class Hub(greenlet):
loop
.
run
()
finally
:
loop
.
error_handler
=
None
# break the refcount cycle
self
.
parent
.
throw
(
LoopExit
(
'This operation would block forever'
))
self
.
parent
.
throw
(
LoopExit
(
'This operation would block forever'
,
self
))
# this function must never return, as it will cause switch() in the parent greenlet
# to return an unexpected value
# It is still possible to kill this greenlet with throw. However, in that case
...
...
gevent/pool.py
View file @
e7f64dc2
...
...
@@ -197,7 +197,17 @@ class GroupMappingMixin(object):
return
greenlet
def
apply
(
self
,
func
,
args
=
None
,
kwds
=
None
):
"""Equivalent of the apply() builtin function. It blocks till the result is ready."""
"""
Rough quivalent of the :func:`apply()` builtin function blocking until
the result is ready and returning it.
The ``func`` will *usually*, but not *always*, be run in a way
that allows the current greenlet to switch out (for example,
in a new greenlet or thread, depending on implementation). But
if the current greenlet or thread is already one that was
spawned by this pool, the pool may choose to immediately run
the `func` synchronously.
"""
if
args
is
None
:
args
=
()
if
kwds
is
None
:
...
...
gevent/threadpool.py
View file @
e7f64dc2
...
...
@@ -235,8 +235,12 @@ class ThreadPool(GroupMappingMixin):
return
self
.
apply
(
function
,
args
,
kwargs
)
def
_apply_immediately
(
self
):
# we always pass apply() off to the threadpool
return
False
# If we're being called from a different thread than the one that
# created us, e.g., because a worker task is trying to use apply()
# recursively, we have no choice but to run the task immediately;
# if we try to AsyncResult.get() in the worker thread, it's likely to have
# nothing to switch to and lead to a LoopExit.
return
get_hub
()
is
not
self
.
hub
def
_apply_async_cb_spawn
(
self
,
callback
,
result
):
callback
(
result
)
...
...
greentest/test__threadpool.py
View file @
e7f64dc2
...
...
@@ -212,6 +212,23 @@ class TestPool(TestCase):
class
TestPool2
(
TestPool
):
size
=
2
def
test_recursive_apply
(
self
):
p
=
self
.
pool
def
a
():
return
p
.
apply
(
b
)
def
b
():
# make sure we can do both types of callbacks
# (loop iteration and end-of-loop) in the recursive
# call
gevent
.
sleep
()
gevent
.
sleep
(
0.001
)
return
"B"
result
=
p
.
apply
(
a
)
self
.
assertEqual
(
result
,
"B"
)
class
TestPool3
(
TestPool
):
size
=
3
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment