Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
镜像
tornadoweb
Tornado
提交
f28b2453
Tornado
项目概览
镜像
/
tornadoweb
/
Tornado
大约 1 年 前同步成功
通知
26
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Tornado
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
f28b2453
编写于
5月 14, 2023
作者:
B
Ben Darnell
提交者:
GitHub
5月 14, 2023
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #3029 from minrk/reuse-selector
separate SelectorThread into its own object
上级
b5dad636
91bddc05
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
77 addition
and
44 deletion
+77
-44
tornado/platform/asyncio.py
tornado/platform/asyncio.py
+71
-44
tornado/test/asyncio_test.py
tornado/test/asyncio_test.py
+6
-0
未找到文件。
tornado/platform/asyncio.py
浏览文件 @
f28b2453
...
...
@@ -52,7 +52,7 @@ _T = TypeVar("_T")
# Collection of selector thread event loops to shut down on exit.
_selector_loops
=
set
()
# type: Set[
AddThreadSelectorEventLoop
]
_selector_loops
=
set
()
# type: Set[
SelectorThread
]
def
_atexit_callback
()
->
None
:
...
...
@@ -427,53 +427,18 @@ class AnyThreadEventLoopPolicy(_BasePolicy): # type: ignore
return
loop
class
AddThreadSelectorEventLoop
(
asyncio
.
AbstractEventLoop
)
:
"""
Wrap an event loop to add implementations of the ``add_reader`` method family
.
class
SelectorThread
:
"""
Define ``add_reader`` methods to be called in a background select thread
.
Instances of this class start a second thread to run a selector.
This thread is completely hidden from the user; all callbacks are
run on the wrapped event loop's thread.
This class is used automatically by Tornado; applications should not need
to refer to it directly.
It is safe to wrap any event loop with this class, although it only makes sense
for event loops that do not implement the ``add_reader`` family of methods
themselves (i.e. ``WindowsProactorEventLoop``)
Closing the ``AddThreadSelectorEventLoop`` also closes the wrapped event loop.
This thread is completely hidden from the user;
all callbacks are run on the wrapped event loop's thread.
Typically used via ``AddThreadSelectorEventLoop``,
but can be attached to a running asyncio loop.
"""
# This class is a __getattribute__-based proxy. All attributes other than those
# in this set are proxied through to the underlying loop.
MY_ATTRIBUTES
=
{
"_consume_waker"
,
"_select_cond"
,
"_select_args"
,
"_closing_selector"
,
"_thread"
,
"_handle_event"
,
"_readers"
,
"_real_loop"
,
"_start_select"
,
"_run_select"
,
"_handle_select"
,
"_wake_selector"
,
"_waker_r"
,
"_waker_w"
,
"_writers"
,
"add_reader"
,
"add_writer"
,
"close"
,
"remove_reader"
,
"remove_writer"
,
}
def
__getattribute__
(
self
,
name
:
str
)
->
Any
:
if
name
in
AddThreadSelectorEventLoop
.
MY_ATTRIBUTES
:
return
super
().
__getattribute__
(
name
)
return
getattr
(
self
.
_real_loop
,
name
)
_closed
=
False
def
__init__
(
self
,
real_loop
:
asyncio
.
AbstractEventLoop
)
->
None
:
self
.
_real_loop
=
real_loop
...
...
@@ -519,6 +484,8 @@ class AddThreadSelectorEventLoop(asyncio.AbstractEventLoop):
self
.
_waker_w
.
close
()
def
close
(
self
)
->
None
:
if
self
.
_closed
:
return
with
self
.
_select_cond
:
self
.
_closing_selector
=
True
self
.
_select_cond
.
notify
()
...
...
@@ -527,7 +494,7 @@ class AddThreadSelectorEventLoop(asyncio.AbstractEventLoop):
_selector_loops
.
discard
(
self
)
self
.
_waker_r
.
close
()
self
.
_waker_w
.
close
()
self
.
_
real_loop
.
close
()
self
.
_
closed
=
True
def
_wake_selector
(
self
)
->
None
:
try
:
...
...
@@ -661,3 +628,63 @@ class AddThreadSelectorEventLoop(asyncio.AbstractEventLoop):
return
False
self
.
_wake_selector
()
return
True
class
AddThreadSelectorEventLoop
(
asyncio
.
AbstractEventLoop
):
"""Wrap an event loop to add implementations of the ``add_reader`` method family.
Instances of this class start a second thread to run a selector.
This thread is completely hidden from the user; all callbacks are
run on the wrapped event loop's thread.
This class is used automatically by Tornado; applications should not need
to refer to it directly.
It is safe to wrap any event loop with this class, although it only makes sense
for event loops that do not implement the ``add_reader`` family of methods
themselves (i.e. ``WindowsProactorEventLoop``)
Closing the ``AddThreadSelectorEventLoop`` also closes the wrapped event loop.
"""
# This class is a __getattribute__-based proxy. All attributes other than those
# in this set are proxied through to the underlying loop.
MY_ATTRIBUTES
=
{
"_real_loop"
,
"_selector"
,
"add_reader"
,
"add_writer"
,
"close"
,
"remove_reader"
,
"remove_writer"
,
}
def
__getattribute__
(
self
,
name
:
str
)
->
Any
:
if
name
in
AddThreadSelectorEventLoop
.
MY_ATTRIBUTES
:
return
super
().
__getattribute__
(
name
)
return
getattr
(
self
.
_real_loop
,
name
)
def
__init__
(
self
,
real_loop
:
asyncio
.
AbstractEventLoop
)
->
None
:
self
.
_real_loop
=
real_loop
self
.
_selector
=
SelectorThread
(
real_loop
)
def
close
(
self
)
->
None
:
self
.
_selector
.
close
()
self
.
_real_loop
.
close
()
def
add_reader
(
self
,
fd
:
"_FileDescriptorLike"
,
callback
:
Callable
[...,
None
],
*
args
:
Any
)
->
None
:
return
self
.
_selector
.
add_reader
(
fd
,
callback
,
*
args
)
def
add_writer
(
self
,
fd
:
"_FileDescriptorLike"
,
callback
:
Callable
[...,
None
],
*
args
:
Any
)
->
None
:
return
self
.
_selector
.
add_writer
(
fd
,
callback
,
*
args
)
def
remove_reader
(
self
,
fd
:
"_FileDescriptorLike"
)
->
bool
:
return
self
.
_selector
.
remove_reader
(
fd
)
def
remove_writer
(
self
,
fd
:
"_FileDescriptorLike"
)
->
bool
:
return
self
.
_selector
.
remove_writer
(
fd
)
tornado/test/asyncio_test.py
浏览文件 @
f28b2453
...
...
@@ -21,6 +21,7 @@ from tornado.platform.asyncio import (
AsyncIOLoop
,
to_asyncio_future
,
AnyThreadEventLoopPolicy
,
AddThreadSelectorEventLoop
,
)
from
tornado.testing
import
AsyncTestCase
,
gen_test
...
...
@@ -105,6 +106,11 @@ class AsyncIOLoopTest(AsyncTestCase):
42
,
)
def
test_add_thread_close_idempotent
(
self
):
loop
=
AddThreadSelectorEventLoop
(
asyncio
.
get_event_loop
())
# type: ignore
loop
.
close
()
loop
.
close
()
class
LeakTest
(
unittest
.
TestCase
):
def
setUp
(
self
):
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录