Python:提高性能 - 在单独的线程中写入数据库
Python: Improving performance - Writing to database in seperate thread
我正在 运行 开发一个 python 应用程序,出于各种原因,我不得不将我的程序托管在世界某个地方的服务器上,然后将我的数据库放在另一个地方。
我通过一个简单的脚本进行了测试,从我在邻国的家到数据库服务器,从数据库写入和检索一行的时间大约为 0.035 秒(我认为这是一个不错的速度)与我在世界另一端的 python 服务器执行相同操作时的 0.16 秒相比。
这是一个问题,因为我试图让我的 python 应用程序尽可能快,所以我想知道是否有聪明的方法来做到这一点?
当我运行同步我的代码时,我的程序每次必须写入数据库时都在等待,这大约是每秒 3 次,所以时间加起来了。是否可以 运行 在单独的线程或其他线程中连接到数据库,以便在尝试将数据发送到数据库时不会停止整个程序?还是可以使用 asyncio 来完成(我没有使用异步代码的经验)?
我真的很难找到解决这个问题的好方法。
提前,非常感谢!
是的,您可以创建一个在后台执行写入的线程。在您的情况下,拥有一个队列似乎是合理的,主线程在其中放置要写入的内容,而数据库线程获取并写入它们。队列可以有一个最大深度,这样当有太多东西待处理时,主线程就会等待。你也可以做一些不同的事情,比如放弃发生得太快的事情。或者,使用同步数据库并编写本地副本。您也可能有机会通过一次提交多个来加快写入速度。
这是工作线程的草图
import threading
import queue
class SqlWriterThread(threading.Thread):
def __init__(self, db_connect_info, maxsize=8):
super().__init__()
self.db_connect_info = db_connect_info
self.q = queue.Queue(maxsize)
# TODO: Can expose q.put directly if you don't need to
# intercept the call
# self.put = q.put
self.start()
def put(self, statement):
print(f"DEBUG: Putting\n{statement}")
self.q.put(statement)
def run(self):
db_conn = None
while True:
# get all the statements you can, waiting on first
statements = [self.q.get()]
try:
while True:
statements.append(self.q.get(), block=False)
except queue.Empty:
pass
try:
# early exit before connecting if channel is closed.
if statements[0] is None:
return
if not db_conn:
db_conn = do_my_sql_connect()
try:
print("Debug: Executing\n", "--------\n".join(f"{id(s)} {s}" for s in statements))
# todo: need to detect closed connection, then reconnect and resart loop
cursor = db_conn.cursor()
for statement in statements:
if statement is None:
return
cursor.execute(*statement)
finally:
cursor.commit()
finally:
for _ in statements:
self.q.task_done()
sql_writer = SqlWriterThread(('user', 'host', 'credentials'))
sql_writer.put(('execute some stuff',))
我正在 运行 开发一个 python 应用程序,出于各种原因,我不得不将我的程序托管在世界某个地方的服务器上,然后将我的数据库放在另一个地方。
我通过一个简单的脚本进行了测试,从我在邻国的家到数据库服务器,从数据库写入和检索一行的时间大约为 0.035 秒(我认为这是一个不错的速度)与我在世界另一端的 python 服务器执行相同操作时的 0.16 秒相比。 这是一个问题,因为我试图让我的 python 应用程序尽可能快,所以我想知道是否有聪明的方法来做到这一点?
当我运行同步我的代码时,我的程序每次必须写入数据库时都在等待,这大约是每秒 3 次,所以时间加起来了。是否可以 运行 在单独的线程或其他线程中连接到数据库,以便在尝试将数据发送到数据库时不会停止整个程序?还是可以使用 asyncio 来完成(我没有使用异步代码的经验)?
我真的很难找到解决这个问题的好方法。 提前,非常感谢!
是的,您可以创建一个在后台执行写入的线程。在您的情况下,拥有一个队列似乎是合理的,主线程在其中放置要写入的内容,而数据库线程获取并写入它们。队列可以有一个最大深度,这样当有太多东西待处理时,主线程就会等待。你也可以做一些不同的事情,比如放弃发生得太快的事情。或者,使用同步数据库并编写本地副本。您也可能有机会通过一次提交多个来加快写入速度。
这是工作线程的草图
import threading
import queue
class SqlWriterThread(threading.Thread):
def __init__(self, db_connect_info, maxsize=8):
super().__init__()
self.db_connect_info = db_connect_info
self.q = queue.Queue(maxsize)
# TODO: Can expose q.put directly if you don't need to
# intercept the call
# self.put = q.put
self.start()
def put(self, statement):
print(f"DEBUG: Putting\n{statement}")
self.q.put(statement)
def run(self):
db_conn = None
while True:
# get all the statements you can, waiting on first
statements = [self.q.get()]
try:
while True:
statements.append(self.q.get(), block=False)
except queue.Empty:
pass
try:
# early exit before connecting if channel is closed.
if statements[0] is None:
return
if not db_conn:
db_conn = do_my_sql_connect()
try:
print("Debug: Executing\n", "--------\n".join(f"{id(s)} {s}" for s in statements))
# todo: need to detect closed connection, then reconnect and resart loop
cursor = db_conn.cursor()
for statement in statements:
if statement is None:
return
cursor.execute(*statement)
finally:
cursor.commit()
finally:
for _ in statements:
self.q.task_done()
sql_writer = SqlWriterThread(('user', 'host', 'credentials'))
sql_writer.put(('execute some stuff',))