In web software or service software, program is running in a concurrency situation as multiple thread or process, if create a network connection every time when handle a request, it waste some of performances to establish or close connect. If always use a single connection, we have to face the connection competition situation. So maintain a connection pool is a regular and classic way to solve this problem. I have a web service written in Python with pyramid, it use thrift’s void mode function to report the every request’s statistic and error information to a thrift server, since thrift official client has no client pool support, in order to purchase the extreme performance improvement, I implement a client pool for thrift client.
Basically we create a Pool to maintain all client objects, and create a Client object hold the real thrift client, when this Client object’s reference count is 0, which means it was destroy by python interpreter, recycle the real thrift client to Pool object. It’s really simple and I think I should just show the source code
import threading from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol # it's a network error handler decorator, you can find it here: # https://github.com/vincentwyshan/ZooBus/blob/master/zoobus/thrift/thrifthelper.py from .helper import client_ensure class Pool(object): def __init__(self, host, port, client_cls, pool_size=30): self.pool_size = pool_size self.lock = threading.RLock() self.host = host self.port = port self.client_cls = client_cls self.pool = [] def connect(self): return Client(self) def new_client(self): transport = TSocket.TSocket(self.host, self.port) # Time out 2 seconds transport.setTimeout(1000*2) transport = TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = self.client_cls(protocol) transport.open() return client def check_in(self, client): # print "check in:", id(client), len(self.pool) self.lock.acquire() try: while len(self.pool) >= self.pool_size: self.pool.pop(0) self.pool.append(client) finally: self.lock.release() def check_out(self): self.lock.acquire() try: client = None if len(self.pool) > 0: client = self.pool.pop(0) if not client: client = self.new_client() # print time.time(), "check out:", id(client) return client finally: self.lock.release() class Client(object): def __init__(self, pool): self.client = pool.check_out() self.pool = pool for method in dir(self.client): if(not method.startswith('_') and not method.startswith('recv_') and not method.startswith('send_')): setattr(self, method, client_ensure(getattr(self.client, method))) def _new_client(self): self.client = self.pool.new_client() def close(self): self.pool.check_in(self.client) self.pool = None def __del__(self): if hasattr(self, 'pool') and self.pool: self.pool.check_in(self.client)
Using this logic, you can implement other network connection pool.
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.