viking_unet

multithreaded sqlite connector

Jul 12th, 2020
1,031
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 1.56 KB | None | 0 0
  1. # multithreaded sqlite connector
  2.  
  3. import sqlite3
  4. import time
  5. import threading
  6. import weakref
  7.  
  8.  
  9. # function for get instance of created singleton SQLiter globally in any place of code
  10. def get_sqliter():
  11.     return MetaSingleton._instance[0] if MetaSingleton._instance else None
  12.  
  13. # special class for singleton pattern
  14. class MetaSingleton(type):
  15.     _instance = []
  16.    
  17.     def __call__(cls, *args, **kwargs):
  18.         if not cls._instance:
  19.             cls._instance.append(type.__call__(cls, *args, **kwargs))
  20.         else:
  21.             if args or kwargs:
  22.                 raise Exception("Can't recreate singleton with new args until old will be cleared")
  23.         return weakref.proxy(cls._instance[0])
  24.  
  25. # class SQLiter with singleton pattern
  26. class SQLiter(metaclass = MetaSingleton):
  27.    
  28.     # memory db file and locker for one-in-time execution sql command
  29.     def __init__(self, database):
  30.         self.database = database
  31.         self.lock = threading.Lock()
  32.        
  33.     # delete instance for available to create new instance of singletone
  34.     def clear(self):
  35.         MetaSingleton._instance.pop()
  36.    
  37.     # for execute sql command without return value
  38.     def execute(self, sql, values=[]):
  39.         with self.lock:
  40.             with sqlite3.connect(self.database) as conn:
  41.                 conn.execute(sql, values)
  42.  
  43.     # for execute sql command with return value      
  44.     def select(self, sql, values=[]):
  45.         with self.lock:
  46.             with sqlite3.connect(self.database) as conn:
  47.                 return list(conn.execute(sql, values))
  48.            
  49. if __name__ == '__main__':
  50.    
  51.     sqliter = SQLiter('test.sqlite')
  52.    
  53.     def test_select(number):
  54.         threads = []
  55.         for i in range(number):
  56.             sql, values = """ select 1 """, []
  57.             thread = threading.Thread(target=sqliter.execute, args=(sql, values))
  58.             threads.append(thread)
  59.             thread.start()
  60.         for thread in threads:    
  61.             thread.join()
  62.        
  63.     def test_insert(number):
  64.         sqliter.execute(""" create table if not exists test (id int) """)
  65.         sqliter.execute(""" delete from test """)
  66.         threads = []
  67.         for i in range(number):
  68.             time.sleep(0.001) # need to start >1000 threads, but don't change time statistic (why?)
  69.             sql, values = """ insert into test(id) values(?)""", (i, )
  70.             thread = threading.Thread(target=sqliter.execute, args=(sql, values))
  71.             threads.append(thread)
  72.             thread.start()
  73.         for thread in threads:    
  74.             thread.join()
  75.    
  76.     number = 1000
  77.     t1 = time.monotonic()
  78.     if 1:
  79.         test_select(number)
  80.     elif 0:
  81.         test_insert(number)
  82.     else:
  83.         pass
  84.     t2 = time.monotonic()
  85.    
  86.     # results of tests:
  87.     # select 1 for 1000 times: 0.156
  88.     # insert one row for 1000 times: 4.280 seconds
  89.     # select 1 for 5000 times: 0.790
  90.     # insert one row for 5000 times: 21.483 seconds
  91.     # select 1 for 10000 times: 1.588
  92.     # insert one row for 10000 times: 43.941 seconds
  93.    
  94.     print('done in %.3f seconds' % (t2-t1))
Add Comment
Please, Sign In to add comment