关于 asyncio 创建多个 tcp 连接,线程数不准确的问题

2019-08-14 08:40:58 +08:00
 1462326016

按理说 asyncio 封装了 IO 多路复用,应该是用一个线程通过监听文件描述符的方式来管理多个 tcp 连接,但实际测试中好像为每个 tcp 连接创建了一个线程,但是线程总数有封顶,40 个,这个不是特别理解,为什么不是一个线程对应多个 tcp 连接? 测试代码如下:

# -*- coding: utf-8 -*-
import asyncio
import threading

loop = asyncio.get_event_loop()


async def task():
    print('start11')
    print('当前线程总数:' + threading.activeCount().__str__())
    await asyncio.open_connection('www.baidu.com', 80)
    await asyncio.sleep(10)
    print('stop11')


async def task2():
    print('start22')
    print('全部启动之后线程数:' + threading.activeCount().__str__())
    await asyncio.sleep(13)
    print('stop22')


for a in range(10):
    loop.create_task(task())
print(f'协程任务总数为:{asyncio.Task.all_tasks().__len__()}')
loop.run_until_complete(task2())

输出为:

协程任务总数为:10
start11
当前线程总数:1
start11
当前线程总数:2
start11
当前线程总数:3
start11
当前线程总数:4
start11
当前线程总数:5
start11
当前线程总数:6
start11
当前线程总数:7
start11
当前线程总数:8
start11
当前线程总数:9
start11
当前线程总数:10
start22
全部启动之后线程数:11

如果把 for 循环中任务数改为 100,最后总共会创建 41 个线程,100 个连接。

2582 次点击
所在节点    Python
8 条回复
BBCCBB
2019-08-14 08:44:04 +08:00
你该用 currentThread(0
1462326016
2019-08-14 08:47:07 +08:00
@BBCCBB 可是我要获取的是当前线程总数量,为什么要用 currentThread 呢?
BBCCBB
2019-08-14 09:03:28 +08:00
当前 python 开的所有线程里并不是全部用来跑整个 eventloop

还有其他的用途, 比如还需要 gc 线程等.

照你问题里说的, 你是要看 eventloop 里多个 tcp 的处理是否是同一个线程, 不用 currentThread 用啥???
1462326016
2019-08-14 09:21:21 +08:00
@BBCCBB 感谢回复,我在获取线程数量下方添加了 currentThread 函数,获取到的对象都是同一个 Thread 对象,证实了当前的十个连接都是在同一个线程上的。但是为什么单单在打开 tcp 连接的时候出现这么多线程呢?如果不打开 tcp 连接,只是把 task 函数 sleep 模拟下任务的话就只有一个主线程是活动的,线程数量总是 1。
snBDX1b0jJM4ogKd
2019-08-14 09:35:50 +08:00
asyncio 是多路复用毫无问题,为什么会出现很多线程,是因为你这里的 baidu.com 。asyncio 是扔给线程池做 DNS 解析达到异步效果的,看源码可证实。你把 baidu.com 换成 IP 即可看到效果
1462326016
2019-08-14 09:39:24 +08:00
@cs010 非常感谢, 回答正确, 我试了下的确就是我想要的结果,感谢感谢!我去翻翻源码看看怎么实现的。
gaokevin163
2019-08-14 11:54:45 +08:00
就算没有其他的解析 DNS 或者其他的一些任务 就单单处理 io 的线程也可以有多个,只要每个线程处理的链接不止一个就是多路复用
1462326016
2019-08-14 14:17:19 +08:00
@gaokevin163 恩恩,这个我是了解的,可以通过自己新开线程然后在新的线程中新建事件循环达到多个线程处理 io 的目的。发帖子的目的主要就是弄清楚其他线程是干什么用的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/591690

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX