程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

python 數據庫性能提升 - TCP聊天+傳輸文件服務器服務器套接字v2.6

編輯:Python

剛創建服務器的時候為了後期便於管理, 主要也是MySQL對我不適合, 跨平台使用, 一打包還有得裝, 所以直接自己做了個
這是我寫的服務器的數據庫代碼, 可見一看就能看出來, 數據庫只存在於單個文件data.json中, I/O十分頻繁, 用戶信息文件存於運行內存中, 在小數據的情況下速度快, 但到數據存於一定程度, 性能斷崖式下跌, 且 在taskmgr(任務管理器) 中內存一舉超過了 1.78G的pycharm, 成為第一.

提升性能的方法:

  1. 變量使用 set

    可變,無序的,不重復的元素集合 (不可出現 listsetbytearray 等無__hash__(self)哈希值的類)

    – set 的 時間復雜度為 O1, list 的 時間復雜度為 On.

    – set內部存儲元素必是可hash的,而且還是不可重復的.
    當每一個set中的元素都有一個獨立hash的編碼,雖然外面看元素是亂序的,但是內部其實是hash編碼的排序,當運行時是通過編碼查詢,所以會如此之快(warning:是有可能出現hash沖突,但是極少)

  2. 避免單文件頻繁調用I/O

  3. 用戶建立文件夾, 一個文件夾對應一個用戶的md5值(sha256的都行), 這是為了創建文件夾時候避免非法字符的出現.

  4. 類似於文件傳輸服務器, 傳來的文件最好解壓分割切片

  5. 只將用戶名存於運行內存中, 節省空間, 一般數據庫也不會大於幾TB, 把密碼, 注冊時間這些雜七雜八的東西放在文件夾下面



行了, 後面的直接不用看了, 按左上角的退出鍵退出吧



這是data.py代碼(全部data.py 在gitcode - https://gitcode.net/m0_60394896/python/-/blob/05267ff4f3c2267954dc87e505d034229eaa0f98/server/data.py)

from json import load, dump
from os import path, mkdir
from hashlib import md5
from time import time
def encode(data: str):
m = md5()
m.update(data.encode('utf8'))
return m.hexdigest()
file = '.\clients\data.json'
folder = '.\clients'
if not path.exists(folder):
mkdir(folder)
class data:
def __init__(self):
if path.exists(file):
with open(file, 'r') as f:
self.data = load(f)
else:
self.data = {
}
def __get__(self, username, default=None) -> tuple:
return self.data.get(username, default)
def __in__(self, username) -> bool:
return username in self.data.keys()
def __write__(self) -> None:
with open(file, 'w') as f:
dump(self.data, f, indent=4)
def __register__(self, username, password, time: (int, float) = time()) -> None:
...
self.__write__()
def __login__(self, username, password) -> bool:
return self.data[username][0] == encode(password)
def get_time(self, username):
return self.data[username][1]
def handler(self, type: int, username: str, password: str):
...

TCP聊天+傳輸文件服務器服務器套接字v2.6

文章目錄

  • 測試
  • 提升性能

所有版本記錄:
v1.0 : TCP聊天服務器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread(含日志,html)+anaconda打包32位exe(3.4萬字)|python高階
v1.1 : python TCP套接字服務器v1.1-新增服務端命令功能及修改bug(socket+PyQt5)
v1.2 : python TCP服務器v1.2 - 服務端新增用戶登錄注冊(json, md5加密)
v1.3 : python TCP服務器v1.3 - 服務器抗壓測試及關閉套接字處理
v1.4 : python TCP服務器v1.4 - 客戶端連接服務器異常(異常情況分類)處理
v1.5 : PyQt5可編輯下拉框(comboBox):editable - python TCP服務器v1.5 - 客戶端連接界面增加自定義參數(設置超時, 連接地址可選)
v1.6 : Python TCP服務器v1.6 - multiprocessing多進程及Ctrl-c(SIGINT)退出
v1.7 : Python TCP服務器v1.7 - PyQt5 server服務端來臨
v1.8 : python TCP服務器v1.8 - PyQt5登錄界面美化+淡入淡出
v1.9 : socketTCP協程文件+信息傳遞 - TCP聊天文件服務器v1.9 - 劃時代的版本更新(4.6萬字)
v2.0 : TCP聊天文件服務器v2.0 - 重大bug修復+PyQt5文件傳輸可視化
v2.1 : TCP聊天文件服務器v2.1 - 服務端線程管理(threading.enumerate)
v2.2 : TCP聊天文件服務器v2.2 - 服務端客戶端套接字解決分包/粘包問題 - SocketQueue繼承以及減少冗余
v2.3 : gzip的使用 - TCP聊天文件服務器v2.3 - 文件傳輸建立緩存制度和.gz的解壓縮/壓縮解決運行內存過大
v2.4 : 網絡傳輸測速 - TCP聊天+傳輸文件服務器服務器套接字v2.4 - socket協程文件傳送測速
v2.5 : TCP聊天+傳輸文件服務器服務器套接字v2.5 - socket測速規范已經gzip的棄用
v2.6 : TCP聊天+傳輸文件服務器服務器套接字v2.6 - 登錄注冊界面更新 - loading界面應用

測試

增加數據庫 用戶登錄注冊的時候還是在 v1.2,

import itertools
from threading import Thread
def threading(Daemon, name=None, **kwargs):
thread = Thread(**kwargs)
thread.setDaemon(Daemon)
if name:
thread.setName(name)
thread.start()
return thread
data = data()
print(data.handler(0, "tqm", "asdf"))
a = 0
for u in itertools.product("qwertyuiop[]asdfghjkl;'\\zxcvbnm,./`12345678900-", repeat=6):
p = "阿斯蒂芬asdf"
a += 1
if a % 400 == 0:
data.handler(1, "".join(u), "".join(p), _show_detail=True)
print(a)
else:
data.handler(1, "".join(u), "".join(p), _show_detail=False)
if a > 1000000:
sys.exit(a)
2022-06-20 12:49:00,951 - data.py[line:51] - INFO: Execute the function User handle, timeit 0.000
(False, '用戶不存在!', '')
2022-06-20 12:49:01,743 - data.py[line:51] - INFO:
Execute the function User handle, timeit 0.002
2022-06-20 19:11:20,572 - data.py[line:145] - INFO: size: 799.9Mb(8319541 bytes)
... ...
2022-06-20 19:14:37,143 - data.py[line:51] - INFO: Execute the function User handle, timeit 2.496
2022-06-20 19:14:37,144 - data.py[line:145] - INFO: size: 800.0Mb(8354830 bytes)
2022-06-20 19:17:45,165 - data.py[line:51] - INFO: Execute the function User handle, timeit 2.531
2022-06-20 19:17:45,165 - data.py[line:145] - INFO: size: 800.0Mb(8385887 bytes)

在運行了長達3, 8400次迭代後, 連一個注冊用戶都已經超過了秒的單位.

提升性能

setlistaddappend
from json import load, dump, decoder
from os import path, mkdir, listdir
from hashlib import md5
from time import time
import logging
logging.basicConfig(level=logging.DEBUG,
format="%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)
def _mkdir(_folder):
try:
if not path.exists(_folder):
mkdir(_folder)
return True
except NotImplementedError:
logger.exception("")
return False
def encode(_data: str):
m = md5()
m.update(_data.encode('utf8'))
return m.hexdigest()
def timeit(objname: str, ign=True):
def setup_function(func_name):
def _exec_function(*args, _show_detail=True, **kwargs):
startime = time()
_resp = func_name(*args, **kwargs)
if _show_detail:
logger.info("Execute the function %s%s, timeit %0.3f" % (
objname.title(), "" if ign else f" (at {
str(func_name)})", time() - startime))
return _resp
return _exec_function
return setup_function
folder = r'.\clients'
_mkdir(folder)
data = set()
if path.isdir(folder):
try:
data = set(listdir(folder))
except decoder.JSONDecodeError:
pass
def __in__(username) -> bool:
return username in data
def register(username, password, register_time: (int, float) = time()) -> None:
global data
data.add(username)
user_path = path.join(folder, encode(username))
print(user_path, _mkdir(user_path))
_mkdir(user_path)
with open(path.join(user_path, "user.json"), "w") as f:
dump({
"username": username, "password": password, "register_time": int(register_time)}, f, indent=4)
def login(username, password) -> bool:
with open(path.join(path.join(folder, encode(username)), "user.json"), "r") as f:
_data = load(f)
return _data.get("username", "") == username and _data.get("password", "") == password
def get_time(username):
with open(path.join(path.join(folder, encode(username)), "user.json"), "r") as f:
return load(f).get("register_time")
@timeit("User Handle")
def handler(_type: int, username: str, password: str):
username = username.strip()
if not username:
return False, "未填寫用戶名!", ""
password = password.strip()
if not password:
return False, "未填寫密碼!", ""
if not 2 <= len(username) <= 12:
return False, "用戶名需在2~12位之間!", ""
if not 4 <= len(password) <= 10:
return False, "密碼需在4~10位之間!", ""
if _type == 0: # login
if not __in__(username):
return False, "用戶不存在!", ""
if not login(username, password):
return False, "用戶名 / 密碼錯誤!", ""
return True, "歡迎回來, " + username, username
elif _type == 1: # register
if __in__(username):
return False, "已存在用戶!", ""
register(username, password)
return True, "初來乍到, " + username, username

就是將每個用戶的用戶名的md5值存於文件夾, user.json放信息


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved