Python asyncio:阻塞和竞争条件

时间:2018-06-02 23:12:38

标签: python python-asyncio aiohttp

我正在尝试理解python的asyncio库,并对以下示例的行为感到有些惊讶:

import asyncio
import time

from aiohttp import web


_lock_table = {'locked': False}


async def process(text):
    # wait while we're blocked
    while _lock_table['locked']:
        await asyncio.sleep(1)

    _lock_table['locked'] = True

    # hold the lock for three seconds
    # simulates "processing something"
    await asyncio.sleep(3)

    # release the lock
    _lock_table['locked'] = False


async def request_handler(request):
    text = request.query.get('text')

    start_time = time.time()
    await process(text)
    end_time = time.time()

    return web.Response(
        body='text: {}, request time: {}'.format(text, end_time - start_time),
        content_type='text/html'
    )


app = web.Application()
app.router.add_route('GET', '/', request_handler)

web.run_app(app)

如果我启动上述程序并向http://0.0.0.0:8080打开两个请求,我发现这两个请求大约需要三秒钟才能完成。为什么是这样?第二个请求是否应该被获得锁定的第一个请求阻止?

1 个答案:

答案 0 :(得分:0)

我无法重现你所描述的问题。 aiohttp不鼓励使用全局变量,并建议使用Application对象来支持全局变量。但他们似乎并没有提到线程涉及到这里。它似乎是一个更清晰的代码而不是必需品的一般提示 - 所以你的代码应该没问题......

我使用此示例bash脚本测试了您的代码:

#!/bin/bash

pids=()
range=$(seq 1 10)
url='http://127.0.0.1:8080/?text='
for i in $range; do
    curl -o $i.txt "${url}$(date +%H%M%S)" 2>/dev/null &
    pids[$i]=$!
done

wait ${pids[$@]}

for i in $range; do
    echo "$i $(cat $i.txt)"
done

输出看起来像这样:

1 text: 222331, request time: 24.153167724609375
2 text: 222331, request time: 15.077209711074829
3 text: 222331, request time: 27.17816162109375
4 text: 222331, request time: 6.0150146484375
5 text: 222331, request time: 18.09979248046875
6 text: 222331, request time: 21.1268310546875
7 text: 222331, request time: 3.004944086074829
8 text: 222331, request time: 9.03411865234375
9 text: 222331, request time: 12.050049066543579
10 text: 222331, request time: 30.205841302871704

您可能希望确保实际的开始时间相似。