我想运行几个线程,并且在每个线程中都有独立的异步循环,其中将处理异步例程列表。
每个线程都创建了类 'data' 的本地实例,但实际上它看起来像是线程之间的共享对象。我不明白为什么会这样。
所以,问题是:
这里是代码,不用担心异常、线程加入等问题。简化为示例。
预期输出:
id=1, list a: ['1', '1', '1']
实际输出:
id=1, list a: ['1', '3', '2', '1', '3', '2', '3', '2', '1']
数据处理:
class data:
id = 0
a = []
b = []
def __init__(self, id):
self.id = id
async def load_0(self):
for i in range(0, 3):
self.a.append(str(self.id))
await asyncio.sleep(0.1)
async def load_n(self):
for i in range(0, 3):
self.b.append(str(self.id))
await asyncio.sleep(0.1)
在线程中运行异步任务:
async def thread_loop(loop, id):
tasks = []
d = data(id)
# 0 .. n tasks
tasks.append(asyncio.create_task(d.load_0()))
tasks.append(asyncio.create_task(d.load_n()))
await asyncio.gather(*tasks, return_exceptions = True)
if (id == 1):
print('id=' + str(d.id) + ', list a: ' + str(d.a))
线程中的新事件循环:
def thread_main(id):
loop = asyncio.new_event_loop()
loop.run_until_complete(thread_loop(loop, id))
创建和启动线程:
async def start(threads):
threads.append(threading.Thread(target = thread_main, args = (1,)))
threads.append(threading.Thread(target = thread_main, args = (2,)))
for thread in threads:
thread.start()
while True:
await asyncio.sleep(0.1)
主要内容:
if __name__ == '__main__':
threads = []
loop = asyncio.get_event_loop()
loop.run_until_complete(start(threads))
答案 0 :(得分:2)
您的每个线程都有自己的 data
实例。您可以通过 d = data(id)
获得。您在检查 d.a
和 d.b
时看到这种行为的原因是 它们 在所有线程之间共享。这与线程或 asyncio 无关;这是您定义类的方式。
当您将可变对象分配给类级属性时,这些对象在类的所有实例之间共享。
>>> class C:
... l = []
...
>>> c1 = C()
>>> c2 = C()
>>>
>>> c1.l.append(1)
>>> c2.l
[1]
解决此问题的方法是将初始值的分配移至 __init__
。
>>> class C:
... def __init__(self):
... self.l = []
...
>>> c1 = C()
>>> c2 = C()
>>>
>>> c1.l.append(1)
>>> c2.l
[]
在你的情况下
class data:
id = 0
def __init__(self, id):
self.id = id
self.a = []
self.b = []
您甚至可以从类的定义中删除 id = 0
,因为您在 __init__
中分配了一个值。
class data:
def __init__(self, id):
self.id = id
self.a = []
self.b = []
这可能超出您的需要,尤其是在不知道您的真实代码是什么样子的情况下,但您也可以考虑使用数据类。
from dataclasses import dataclass, field
@dataclass
class data:
id: int
a: list[str] = field(default_factory=list)
b: list[str] = field(default_factory=list)
注意:使用 list[str]
需要 Python 3.10 或 from __future__ import annotations
。否则,您将需要改用 typing.List[str]
。