【问题标题】:Python print loading "animation" while connecting to PostgreSQL database连接到 PostgreSQL 数据库时 Python 打印加载“动画”
【发布时间】:2020-12-14 10:43:24
【问题描述】:

(欢迎提供有关如何改写标题的提示。)

我正在使用 psycopg2 和 asyncio。我想要发生的是用户有一些迹象表明程序正在做某事。我有一个花哨的“\ | / -”动画,但为了简单起见,我希望它每秒打印一个点。

到目前为止我所拥有的:

import psycopg2
import asyncio


async def heartbeat(seconds):
    for sec in range(seconds):
        print(".")
        await asyncio.sleep(1)


async def conn_test():
    conn_params = {"database": "testdb", "user": "postgres",
                   "password": "my_pw"}
    conn = None

    print("Attempting to connect to database...")
    while not conn:
        try:
            conn = psycopg2.connect(**conn_params)

        except (Exception, psycopg2.Error) as error:
            print(error)

        finally:
            if conn:
                conn.close()
                print("Successfully connected to database. Now closing connection...")
            else:
                print("Could not connect to the database. Retrying...")


async def main():
    t1 = loop.create_task(heartbeat(10))
    t2 = conn_test()

    await asyncio.wait([t1, t2])

if __name__ == "__main__":
    loop = asyncio.get_event_loop()

    try:
        loop.run_until_complete(main())
    except Exception as e:
        print(e)
    finally:
        loop.close()

我得到什么(如果我故意阻止它连接)

.
Attempting to connect to database...

(直到 psycopg2 超时。)

我想要什么:

.
Attempting to connect to database...
.
.
.
.
.

(等等)

我试过psycopg2.connect(**conn_params, async_=True),但没有达到我想要的效果。我确实得到了点,但是由于返回了连接对象,即使无法建立连接,我的其余代码也无法按预期工作。我尝试进一步研究 async psycopg2。但这种方法似乎带来了很多额外的工作。我只是希望它异步连接,但是一旦连接存在,我的execute()s 肯定不能异步工作。

【问题讨论】:

  • conn_test 不会等待任何东西,因此在完成之前不会给其他任何东西运行的机会。您应该考虑使用异步感知驱动程序。不过,这仍然可能不会让您获得想要的结果。您最好使用单独的线程或进程来更新 UI。
  • 我尝试了conn = await psycopg2.connect(**conn_params),但后来我得到了object psycopg2.extensions.connection can't be used in 'await' expression
  • 对。 psycopg2 不是异步感知库。您需要使用不同的库,例如 asyncpg。
  • 但是一旦连接存在,我的execute()s 肯定不能异步工作 - 如果你在这里写的是真的,你不会对asyncpg 满意.异步不是您可以在程序的一小部分(如辅助线程)中使用的东西,它是一个影响一切的架构决策。
  • 你需要把await放在每个前面。

标签: python python-3.x asynchronous python-asyncio psycopg2


【解决方案1】:

按照 dirn 的建议,我使用 asyncpg 重写了代码:

import asyncpg
import asyncio


async def heartbeat(seconds):
    for sec in range(seconds):
        print(".")
        await asyncio.sleep(1)


async def conn_test():
    conn_params = {"database": "testdb", "user": "postgres",
                   "password": "my_pw"}
    conn = None

    print("Attempting to connect to database...")
    while not conn:
        try:
            conn = await asyncpg.connect(**conn_params)

        except TimeoutError:
            print("Could not connect to the database. Retrying...")

        finally:
            if conn:
                print("Successfully connected to database. "
                      "Now closing connection...")
                await conn.close()


async def main():
    t1 = loop.create_task(heartbeat(10))
    t2 = conn_test()

    await asyncio.wait([t1, t2])

if __name__ == "__main__":
    loop = asyncio.get_event_loop()

    try:
        loop.run_until_complete(main())
    except Exception as e:
        print(e)
    finally:
        loop.close()

这在这个特定示例中产生了预期的结果。现在看看它如何与我的程序的其余部分一起工作......

【讨论】:

  • 请使用asyncio.gather(t1, t2) 而不是asyncio.wait([t1, t2]),因为等待asyncio.wait() 而不使用它的返回值会默默地丢弃异常。此外,您可以将整个最后一个顶级块替换为 asyncio.run(main()),这是从 Python 3.7 开始运行异步代码的首选方式。
  • 感谢您的提示。是的,我只是遵循了一些 Youtube 教程,在那里他尝试了所有内容。还是应该在某个地方有一个 loop.close() 吗?
猜你喜欢
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
  • 2021-07-17
  • 2017-07-06
  • 2019-07-04
相关资源
最近更新 更多