0%

python | 多线程中的 event loop

这篇文章算是

的延伸。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import asyncio
import traceback
from concurrent.futures import ThreadPoolExecutor, as_completed

import aiohttp


class T:

async def get(self, index):
async with aiohttp.ClientSession() as session:
for j in range(10):
async with session.get("http://www.baidu.com") as r:
t = await r.text()
print(index)


test = T()


def main(index):
asyncio.run(test.get(index))


if __name__ == '__main__':
task_list = []
pools = ThreadPoolExecutor(5)
for i in range(5):
task_list.append(pools.submit(main, i))

# 阻塞主进程
for result in as_completed(task_list):
data = result.result()

print("end")

上面的代码运行是没有问题的。

如果改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import asyncio
import traceback
from concurrent.futures import ThreadPoolExecutor, as_completed

import aiohttp


class T:

async def get(self, index):
async with aiohttp.ClientSession() as session:
for j in range(10):
async with session.get("http://www.baidu.com") as r:
t = await r.text()
print(index)


test = T()


def main(index):
loop = asyncio.get_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(test.get(index))


if __name__ == '__main__':
task_list = []
pools = ThreadPoolExecutor(5)
for i in range(5):
task_list.append(pools.submit(main, i))

# 阻塞主进程
for result in as_completed(task_list):
data = result.result()

print("end")

则会报错

RuntimeError: There is no current event loop in thread 'ThreadPoolExecutor-0_0'.

这是因为,主线程可以通过 get_event_loop 获得一个 event loop,但是,多线程是不行的,需要明面申请。

所以,可以改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import asyncio
import traceback
from concurrent.futures import ThreadPoolExecutor, as_completed

import aiohttp


class T:

async def get(self, index):
async with aiohttp.ClientSession() as session:
for j in range(10):
async with session.get("http://www.baidu.com") as r:
t = await r.text()
print(index)


test = T()


def main(index):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(test.get(index))


if __name__ == '__main__':
task_list = []
pools = ThreadPoolExecutor(5)
for i in range(5):
task_list.append(pools.submit(main, i))

# 阻塞主进程
for result in as_completed(task_list):
data = result.result()

print("end")

上面 3 个例子清晰的表明了如何在多线程中使用协程。

有的人认为这不是脱裤子放屁,多此一举吗?直接一个协程不就行了吗,而且,多线程还有切换的开销,这样做不是降低速度吗?

在多线程中用协程,是和使用场景有关系的,不过在这里不再展开。

请我喝杯咖啡吧~