Skip to content

Commit 3e2b87c

Browse files
author
=
committed
Update benchmarks
1 parent e5cc3b1 commit 3e2b87c

File tree

4 files changed

+115
-8
lines changed

4 files changed

+115
-8
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ Easy to use , buy may not the best practice for efficiency concern.
2121
- Nearly all the same with aiomysql (with very limited functions of cource)
2222
- No automaticly date format transition built-in.
2323

24+
## Performance
25+
query type | asynchronous multithreading | synchronous multithreading | synchronous single thread
26+
-|-|-|-
27+
fast single line query | 4864.96 q/s | 5859.20 q/s | 8209.536 q/s
28+
fast single line insertion | N/A (todo) | N/A | N/A
29+
30+
*/\* Test platform: \*/*<br>
31+
*AMD Ryzen 3700x*<br>
32+
*Windows 10 LTSC*<br>
33+
*Oracle 19c*<br>
34+
*You can find performance test codes [here](https://github.com/GoodManWEN/cx_Oracle_async/blob/main/misc).*
35+
2436
## Example
2537
```Python3
2638
# all_usages.py

cx_Oracle_async/utils.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
import asyncio
2-
import cx_Oracle as csor
31
from ThreadPoolExecutorPlus import ThreadPoolExecutor
2+
import cx_Oracle as csor
3+
import platform
4+
import asyncio
5+
import os
6+
7+
pltfm = platform.system()
8+
if pltfm == 'Windows':
9+
DEFAULT_MAXIMUM_WORKER_NUM = (os.cpu_count() or 1) * 16
10+
DEFAULT_MAXIMUM_WORKER_TIMES = 2
11+
elif pltfm == 'Linux' or pltfm == 'Darwin':
12+
DEFAULT_MAXIMUM_WORKER_NUM = (os.cpu_count() or 1) * 32
13+
DEFAULT_MAXIMUM_WORKER_TIMES = 3
414

515
class AsyncCursorWarpper:
616

@@ -76,10 +86,7 @@ async def __aexit__(self, exc_type, exc, tb):
7686
class AsyncPoolWarpper:
7787

7888
def __init__(self , pool , loop = None):
79-
80-
def _test():
81-
...
82-
89+
8390
if loop == None:
8491
loop = asyncio.get_running_loop()
8592
'''
@@ -90,7 +97,8 @@ def _test():
9097
9198
Issue if you have better implementation.
9299
'''
93-
self._thread_pool = ThreadPoolExecutor()
100+
self._thread_pool = ThreadPoolExecutor(max_workers = max(DEFAULT_MAXIMUM_WORKER_NUM , pool.max << DEFAULT_MAXIMUM_WORKER_TIMES))
101+
self._thread_pool.set_daemon_opts(min_workers = max(4 , pool.min << 1))
94102
self._loop = loop
95103
self._pool = pool
96104

@@ -104,7 +112,6 @@ def _test():
104112

105113
await self._loop.run_in_executor(self._thread_pool , _test)
106114

107-
108115
async def create_pool(host = 'localhost', port = '1521' , user = 'sys', password = '', db = 'orcl', loop = None, minsize = 2 , maxsize = 4 , encoding = 'UTF-8' , autocommit=False):
109116
if loop == None:
110117
loop = asyncio.get_running_loop()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class Counter:
2+
3+
def __init__(self):
4+
self.success = 0
5+
self.fail = 0
6+
7+
async def single_thread_fetching(oracle_pool , counter):
8+
SQL = "SELECT DEPTNO FROM SCOTT.DEPT WHERE DEPTNO = 10"
9+
async with oracle_pool.acquire() as connection:
10+
async with connection.cursor() as cursor:
11+
while True:
12+
await cursor.execute(SQL)
13+
r = await cursor.fetchone()
14+
if r and r[0] == 10:
15+
counter.success += 1
16+
else:
17+
counter.fail += 1
18+
19+
async def report_thread(counter , oracle_pool):
20+
st_time = time.time()
21+
while True:
22+
await asyncio.sleep(2)
23+
time_passed = time.time() - st_time
24+
print(f"Report every 2 secs : [success] {counter.success} \t[fail] {counter.fail} \t[qps] {'%.2f' % round(counter.success / time_passed , 2)} \t[time_passed] {'%.2f' % round(time_passed,2)}s")
25+
26+
async def main():
27+
loop = asyncio.get_running_loop()
28+
oracle_pool = await cx_Oracle_async.create_pool(
29+
host='localhost',
30+
port='1521',
31+
user='system',
32+
password='123456',
33+
db='orcl',
34+
loop=loop,
35+
autocommit=False,
36+
minsize = 2,
37+
maxsize = THREAD_NUM,
38+
)
39+
counter = Counter()
40+
loop = asyncio.get_running_loop()
41+
for _ in range(THREAD_NUM):
42+
loop.create_task(single_thread_fetching(oracle_pool , counter))
43+
loop.create_task(report_thread(counter , oracle_pool))
44+
while True:
45+
await asyncio.sleep(3600)
46+
47+
if __name__ == '__main__':
48+
import asyncio
49+
import cx_Oracle_async
50+
import time
51+
import os
52+
THREAD_NUM = (os.cpu_count() or 1) << 2
53+
asyncio.run(main())
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from concurrent.futures import ThreadPoolExecutor
2+
import cx_Oracle
3+
import os
4+
import time
5+
6+
class Counter:
7+
8+
def __init__(self , num):
9+
self.success = [0 for _ in range(num)]
10+
self.fail = [0 for _ in range(num)]
11+
12+
def single_thread(pool , counter , _id):
13+
SQL = "SELECT DEPTNO FROM SCOTT.DEPT WHERE DEPTNO = 10"
14+
connection = pool.acquire()
15+
cursor = connection.cursor()
16+
while True:
17+
cursor.execute(SQL)
18+
r = cursor.fetchone()
19+
if r and r[0] == 10:
20+
counter.success[_id] += 1
21+
else:
22+
counter.fail[_id] += 1
23+
# break
24+
25+
THREAD_NUM = (os.cpu_count() or 1) << 1
26+
pool = cx_Oracle.SessionPool("system", "123456", "localhost:1521/orcl" , min =1 , max = 4 , increment = 1 , threaded = True , encoding = 'UTF-8')
27+
counter = Counter(THREAD_NUM)
28+
with ThreadPoolExecutor(max_workers = THREAD_NUM << 5) as executor:
29+
for _ in range(THREAD_NUM):
30+
executor.submit(single_thread , pool , counter , _)
31+
st_time = time.time()
32+
while True:
33+
time.sleep(2)
34+
time_passed = time.time() - st_time
35+
print(f"Report every 2 secs : [success] {sum(counter.success)} \t[fail] {sum(counter.fail)} \t[qps] {'%.2f' % round(sum(counter.success) / time_passed , 2)} \t[time_passed] {'%.2f' % round(time_passed,2)}s")

0 commit comments

Comments
 (0)