如何提高许多附加到列表的性能?
How to improve performance of many appends to a list?
如何提高以下代码的性能?
BANNED_DOORBOTS = {...}
async def execute_query(self, query):
async with self.pool.acquire() as conn:
async with conn.cursor() as cur:
await cur.execute(query)
records = []
async for row in cur:
if row[0] not in BANNED_DOORBOTS:
records.append({
'key1': row[0],
'key2': row[1]
})
return records
我不想每次都检查if row[0] not in BANNED_DOORBOTS
。
如何避免这种情况?
通常,我在 records
中有一百多个(最多 20 000 个)元素。也许我可以预先分配一些 space 以避免重新分配?
您每次都从数据库查询中重建列表。
我会要求 数据库 不要 return 被禁止的记录:
from psycopg2 import sql # safe SQL composing
# Add a NOT IN clause to filter out banned doorbots, generating a
# separate parameter placeholder per value
query = sql.SQL(query) + sql.SQL(' WHERE ding_id NOT IN ({})').format(
sql.SQL(', ').join([sql.Placeholder()] * len(BANNED_DOORBOTS)))
await cur.execute(query, BANNED_DOORBOTS)
我在这里使用 psycopg.sql
framework 进行合成,但您也可以使用字符串格式(使用 '%s'
作为占位符)。
考虑将 BANNED_DOORBOTS
集放入数据库中的 table 中,这样您就可以使用 WHERE ding_id NOT IN (SELECT id from BANNED_DOORBOTS WHERE id IS NOT NULL)
子查询。这样您仍然可以获得更好的性能(数据库可以为此进行优化),并且您不必生成占位符。
接下来,使用列表理解来构建列表。这样速度更快,因为它避免了重复 list.append
查找和方法调用。将您的列名定义为元组并将其与每一行一起压缩:
keys = ('ding_id', 'doorbot_id', 'created_at', 'address', 'latitude',
'longitude', 'ding_kind')
return [dict(zip(keys, row)) async for row in cur]
async for
列表理解语法需要 Python 3.6 或更新版本。
aiopg
驱动程序允许您配置另一个游标工厂,already produces dictionaries,它可能会更快。然后,您根本不必使用任何列表推导式:
from psycopg2.extras import RealDictCursor
# configure cursor to yield dictionaries rather than tuples
async with conn.cursor(cursor_factory=RealDictCursor) as cur:
await cur.execute(query, BANNED_DOORBOTS)
# directly return the cursor; have the caller do the async iteration
return cur
如果您不想让调用者负责循环,但有生成列表,请使用cursor.fetchall()
method生成该列表;每个元素都是一个字典:
# configure cursor to yield dictionaries rather than tuples
async with conn.cursor(cursor_factory=RealDictCursor) as cur:
await cur.execute(query, BANNED_DOORBOTS)
return await cur.fetchall()
如何提高以下代码的性能?
BANNED_DOORBOTS = {...}
async def execute_query(self, query):
async with self.pool.acquire() as conn:
async with conn.cursor() as cur:
await cur.execute(query)
records = []
async for row in cur:
if row[0] not in BANNED_DOORBOTS:
records.append({
'key1': row[0],
'key2': row[1]
})
return records
我不想每次都检查if row[0] not in BANNED_DOORBOTS
。
如何避免这种情况?
通常,我在 records
中有一百多个(最多 20 000 个)元素。也许我可以预先分配一些 space 以避免重新分配?
您每次都从数据库查询中重建列表。
我会要求 数据库 不要 return 被禁止的记录:
from psycopg2 import sql # safe SQL composing
# Add a NOT IN clause to filter out banned doorbots, generating a
# separate parameter placeholder per value
query = sql.SQL(query) + sql.SQL(' WHERE ding_id NOT IN ({})').format(
sql.SQL(', ').join([sql.Placeholder()] * len(BANNED_DOORBOTS)))
await cur.execute(query, BANNED_DOORBOTS)
我在这里使用 psycopg.sql
framework 进行合成,但您也可以使用字符串格式(使用 '%s'
作为占位符)。
考虑将 BANNED_DOORBOTS
集放入数据库中的 table 中,这样您就可以使用 WHERE ding_id NOT IN (SELECT id from BANNED_DOORBOTS WHERE id IS NOT NULL)
子查询。这样您仍然可以获得更好的性能(数据库可以为此进行优化),并且您不必生成占位符。
接下来,使用列表理解来构建列表。这样速度更快,因为它避免了重复 list.append
查找和方法调用。将您的列名定义为元组并将其与每一行一起压缩:
keys = ('ding_id', 'doorbot_id', 'created_at', 'address', 'latitude',
'longitude', 'ding_kind')
return [dict(zip(keys, row)) async for row in cur]
async for
列表理解语法需要 Python 3.6 或更新版本。
aiopg
驱动程序允许您配置另一个游标工厂,already produces dictionaries,它可能会更快。然后,您根本不必使用任何列表推导式:
from psycopg2.extras import RealDictCursor
# configure cursor to yield dictionaries rather than tuples
async with conn.cursor(cursor_factory=RealDictCursor) as cur:
await cur.execute(query, BANNED_DOORBOTS)
# directly return the cursor; have the caller do the async iteration
return cur
如果您不想让调用者负责循环,但有生成列表,请使用cursor.fetchall()
method生成该列表;每个元素都是一个字典:
# configure cursor to yield dictionaries rather than tuples
async with conn.cursor(cursor_factory=RealDictCursor) as cur:
await cur.execute(query, BANNED_DOORBOTS)
return await cur.fetchall()