环境:
Ubuntu 18.04
Python 3.6.6
以下是代码示例:
import threading
import asyncio
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(3)
def thread_run():
i = 0
for x in range(10):
i += 1
print(x, threading.get_ident())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
for x in range(2):
loop.run_in_executor(executor, thread_run)
loop.run_forever()
输出:
0 140522512643840
1 140522512643840
2 140522512643840
3 140522512643840
4 140522512643840
5 140522512643840
6 140522512643840
7 140522512643840
0 140522504251136
1 140522504251136
2 140522504251136
3 140522504251136
4 140522504251136
5 140522504251136
6 140522504251136
7 140522504251136
8 140522504251136
9 140522504251136
8 140522512643840
9 140522512643840
问题:
如何防止为thread_run
函数切换“上下文”?
如何使某些功能“原子化”?
预期结果(保留多个线程):
0 140522512643840
...
9 140522512643840
0 140522504251136
...
9 140522504251136
PS:是保持调用thread_run
的方法(loop.run_in_executor)所必需的。这只是简化的示例。我只询问案例,在示例中进行了描述。我知道,有很多方法可以重构代码并摆脱loop.run_in_executor
,但是我尝试在这种特殊情况下找到解决方案。
PSS::在Windows 10中具有相同的行为(循环最多增加了100个)
67 8704
16 14712
68 8704
69 8704
70 8704
17 14712
71 8704
更新:#1 我正在尝试使用Decocator :(来自this answer)
def synchronized(wrapped):
lock = threading.Lock()
@functools.wraps(wrapped)
def _wrap(*args, **kwargs):
with lock:
result = wrapped(*args, **kwargs)
return result
但是它对某些功能无效:
import threading
import asyncio
import functools
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(3)
def synchronized(wrapped):
lock = threading.Lock()
@functools.wraps(wrapped)
def _wrap(*args, **kwargs):
with lock:
result = wrapped(*args, **kwargs)
return result
return _wrap
@synchronized
def thread_run():
i = 0
for x in range(5):
i += 1
print(x, "thread_run", threading.get_ident())
@synchronized
def thread_run2():
i = 0
for x in range(5):
i += 1
print(x, "thread_run2", threading.get_ident())
def not_important():
i = 0
for x in range(5):
i += 1
print(x, "not_important", threading.get_ident())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_in_executor(executor, thread_run)
loop.run_in_executor(executor, thread_run2)
loop.run_in_executor(executor, not_important)
loop.run_forever()
输出:
0 thread_run 140039310980864
0 thread_run2 140039302588160
0 not_important 140039220623104
1 not_important 140039220623104
2 not_important 140039220623104
1 thread_run2 140039302588160
2 thread_run2 140039302588160
3 thread_run2 140039302588160
4 thread_run2 140039302588160
3 not_important 140039220623104
4 not_important 140039220623104
1 thread_run 140039310980864
2 thread_run 140039310980864
3 thread_run 140039310980864
4 thread_run 140039310980864
预期:
每个功能(not_important
除外)均按顺序运行。不是并行的。
更新#2: 我添加了“半”解决方案的答案。但是,当您要“拼写”一个不应与任何其他功能插值的功能时,并不能解决问题。
答案 0 :(得分:1)
当前解决方案(尚未完全解决)基于评论@shmee
import threading
import asyncio
import functools
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(3)
def synchronized(wrapped):
@functools.wraps(wrapped)
def _wrap(*args, **kwargs):
with lock:
result = wrapped(*args, **kwargs)
return result
return _wrap
@synchronized
def thread_run():
i = 0
for x in range(10):
i += 1
print(x, "thread_run", threading.get_ident())
@synchronized
def thread_run2():
i = 0
for x in range(10):
i += 1
print(x, "thread_run2", threading.get_ident())
def not_important():
i = 0
for x in range(10):
i += 1
print(x, "not_important", threading.get_ident())
if __name__ == '__main__':
lock = threading.Lock() # global lock
loop = asyncio.get_event_loop()
for x in range(5):
loop.run_in_executor(executor, thread_run)
loop.run_in_executor(executor, thread_run2)
loop.run_in_executor(executor, not_important)
loop.run_forever()
输出:
0 thread_run 140192637171456
1 thread_run 140192637171456
2 thread_run 140192637171456
3 thread_run 140192637171456
4 thread_run 140192637171456
5 thread_run 140192637171456
6 thread_run 140192637171456
7 thread_run 140192637171456
8 thread_run 140192637171456
9 thread_run 140192637171456
0 thread_run2 140192637171456
1 thread_run2 140192637171456
2 thread_run2 140192637171456
3 thread_run2 140192637171456
4 thread_run2 140192637171456
5 thread_run2 140192637171456
6 thread_run2 140192637171456
7 thread_run2 140192637171456
8 thread_run2 140192637171456
9 thread_run2 140192637171456
0 not_important 140192620386048
1 not_important 140192620386048
2 not_important 140192620386048
3 not_important 140192620386048
0 thread_run 140192637171456
1 thread_run 140192637171456
2 thread_run 140192637171456
3 thread_run 140192637171456
4 thread_run 140192637171456
5 thread_run 140192637171456
6 thread_run 140192637171456
7 thread_run 140192637171456
8 thread_run 140192637171456
9 thread_run 140192637171456
0 thread_run2 140192637171456
1 thread_run2 140192637171456
2 thread_run2 140192637171456
3 thread_run2 140192637171456
4 thread_run2 140192637171456
4 not_important 140192620386048
5 not_important 140192620386048
6 not_important 140192620386048
7 not_important 140192620386048
8 not_important 140192620386048
9 not_important 140192620386048
0 not_important 140192620386048
1 not_important 140192620386048
2 not_important 140192620386048
3 not_important 140192620386048
4 not_important 140192620386048
5 not_important 140192620386048
6 not_important 140192620386048
7 not_important 140192620386048
8 not_important 140192620386048
9 not_important 140192620386048
5 thread_run2 140192637171456
6 thread_run2 140192637171456
7 thread_run2 140192637171456
8 thread_run2 140192637171456
9 thread_run2 140192637171456
0 not_important 140192637171456
1 not_important 140192637171456
2 not_important 140192637171456
3 not_important 140192637171456
4 not_important 140192637171456
5 not_important 140192637171456
0 thread_run 140192620386048
1 thread_run 140192620386048
6 not_important 140192637171456
7 not_important 140192637171456
8 not_important 140192637171456
9 not_important 140192637171456
2 thread_run 140192620386048
3 thread_run 140192620386048
4 thread_run 140192620386048
5 thread_run 140192620386048
6 thread_run 140192620386048
7 thread_run 140192620386048
8 thread_run 140192620386048
9 thread_run 140192620386048
0 thread_run2 140192628778752
1 thread_run2 140192628778752
2 thread_run2 140192628778752
3 thread_run2 140192628778752
4 thread_run2 140192628778752
5 thread_run2 140192628778752
6 thread_run2 140192628778752
7 thread_run2 140192628778752
8 thread_run2 140192628778752
9 thread_run2 140192628778752
0 thread_run 140192637171456
1 thread_run 140192637171456
2 thread_run 140192637171456
3 thread_run 140192637171456
4 thread_run 140192637171456
5 thread_run 140192637171456
6 thread_run 140192637171456
7 thread_run 140192637171456
0 not_important 140192628778752
1 not_important 140192628778752
2 not_important 140192628778752
3 not_important 140192628778752
4 not_important 140192628778752
5 not_important 140192628778752
6 not_important 140192628778752
7 not_important 140192628778752
8 not_important 140192628778752
9 not_important 140192628778752
8 thread_run 140192637171456
9 thread_run 140192637171456
0 thread_run2 140192620386048
1 thread_run2 140192620386048
2 thread_run2 140192620386048
3 thread_run2 140192620386048
4 thread_run2 140192620386048
5 thread_run2 140192620386048
6 thread_run2 140192620386048
7 thread_run2 140192620386048
8 thread_run2 140192620386048
9 thread_run2 140192620386048
0 thread_run 140192628778752
1 thread_run 140192628778752
2 thread_run 140192628778752
3 thread_run 140192628778752
4 thread_run 140192628778752
5 thread_run 140192628778752
6 thread_run 140192628778752
7 thread_run 140192628778752
8 thread_run 140192628778752
9 thread_run 140192628778752
0 not_important 140192637171456
1 not_important 140192637171456
2 not_important 140192637171456
3 not_important 140192637171456
4 not_important 140192637171456
5 not_important 140192637171456
0 thread_run2 140192620386048
1 thread_run2 140192620386048
2 thread_run2 140192620386048
3 thread_run2 140192620386048
4 thread_run2 140192620386048
5 thread_run2 140192620386048
6 thread_run2 140192620386048
7 thread_run2 140192620386048
8 thread_run2 140192620386048
9 thread_run2 140192620386048
6 not_important 140192637171456
7 not_important 140192637171456
8 not_important 140192637171456
9 not_important 140192637171456
当前结果:
函数thread_run
和thread_run2
没有冲突。但是它们可能会被not_important
函数打断。
因此,这部分解决了我的问题。我想找到一种方法来防止其他任何函数中断thread_run
和thread_run2
函数。因为在实际的项目中,还有许多其他方法/功能,我无法为所有这些方法/功能添加synchronized
。
答案 1 :(得分:0)
run_in_executor
返回一个将来,您可以等待存档顺序执行
import asyncio
import threading
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(3)
def thread_run():
i = 0
for x in range(10):
i += 1
print(x, threading.get_ident())
async def run(loop):
for _ in range(2):
await loop.run_in_executor(executor, thread_run)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
asyncio.ensure_future(run(loop))
loop.run_forever()