Nic*_*yan 4 python multithreading sqlalchemy
文档说连接池也不是为多线程设计的:
至关重要的是,在使用连接池时以及在通过create_engine()创建的Engine使用扩展池时,池化的连接不得共享给分叉的进程。TCP连接表示为文件描述符,它们通常跨进程边界工作,这意味着它将代表两个或多个完全独立的Python解释器状态并发访问文件描述符。
据我了解,如果我创建连接池:
self.engine = create_engine('postgresql://{user}:{password}@{host}:{port}/{db}'.format(
user=Configuration().get(section='repository', option='user'),
password=Configuration().get(section='repository', option='password'),
host=Configuration().get(section='repository', option='host'),
port=Configuration().get(section='repository', option='port'),
db=Configuration().get(section='repository', option='database')
), echo=False, pool_size=3)
self.session = sessionmaker(self.engine, expire_on_commit=False)
Run Code Online (Sandbox Code Playgroud)
然后self.session()在不同的线程中调用,我将拥有3个不同的连接,分别在N个不同的线程中使用。这是否意味着只有3个并发线程会执行某些工作,而其他线程会等到一个或多个线程将被调用session.close()?还是有可能> 2个线程同时使用同一连接?
NullPool是否更安全(因为每个新会话都是一个新连接)还是没有?
self.engine = create_engine('postgresql://{user}:{password}@{host}:{port}/{db}'.format(
user=Configuration().get(section='repository', option='user'),
password=Configuration().get(section='repository', option='password'),
host=Configuration().get(section='repository', option='host'),
port=Configuration().get(section='repository', option='port'),
db=Configuration().get(section='repository', option='database')
), echo=False, poolclass=NullPool)
Run Code Online (Sandbox Code Playgroud)
一般问题:在这种情况下可以使用相同的连接池:
engine = create_engine('connection_string', echo=False, pool_size=3)
Session = sessionmaker(engine)
def some_function():
session = Session()
...
pool = Pool(processes=10)
pool.map(some_function)
pool.close()
pool.join()
Run Code Online (Sandbox Code Playgroud)
总而言之,线程和进程之间似乎混合在一起。该问题首先询问SQLAlchemy连接池是否是线程安全的,但以使用的代码示例结尾multiprocessing。对于“一般问题”的简短回答是:不,如果使用分叉,则不应在进程边界上共享引擎及其关联的连接池。但是也有例外。
池实现本身是线程安全的,并且通过代理实现Engine也是线程安全的,因为引擎除了保留对池的引用外不保存状态。另一方面,从池中检出的连接不是线程安全的,也不是aSession。
文档说连接池也不是为多线程设计的:
有点误读,因为文档中的原始引用是关于在使用分叉的情况下在进程边界上共享连接池的。这可能会导致麻烦,因为在SQLAlchemy和DB-API层下面通常有一个TCP / IP套接字或文件句柄,并且不应同时对其进行操作。
在这种特殊情况下,使用a NullPool是安全的,而其他情况则不安全,因为它根本不合并,因此进程之间不会共享连接,除非一个人尽力做到这一点。
这是否意味着只有3个并发线程会执行某些工作,而其他线程会等到一个或多个线程将被调用
session.close()?
假设QueuePool正在使用a,则设置的大小不是硬限制,并且存在一定的溢出空间。大小确定了要在池中持久保留的连接数。如果达到溢出限制,则在没有可用连接timeout的情况下TimeoutError,呼叫将等待几秒钟,然后放弃并提出a 。
还是有可能> 2个线程同时使用同一连接?
除了a之外,两个或多个线程将无法从一个池中意外检出相同的连接StaticPool,但是一个线程可以在(不)之后在线程之间显式共享它。
最后,“使用引擎和连接-基本用法”涵盖了问题的主要部分:
单个
Engine管理代表过程的许多个体DBAPI连接和意在在并行的方式被称为 [加上强调]。...
对于使用
os.fork系统调用的多进程应用程序(例如Pythonmultiprocessing模块),通常需要Engine为每个子进程使用一个单独的进程。这是因为Engine维护对最终引用DBAPI连接的连接池的引用-这些连接往往不能跨进程边界移植。一个Engine被配置为不使用池(其经由的使用来实现NullPool)不具有此要求。
| 归档时间: |
|
| 查看次数: |
2249 次 |
| 最近记录: |