锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

python 数据库性能提升 - TCP聊天+传输文件服务器服务器套接字v2.7

时间:2023-02-20 07:30:00 连接器ff18

TCP聊天 传输文件服务器服务器套接字v2.7

刚创建服务器时,为便于后期管理, 主要也是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):
		...

文章目录

  • 测试
  • 提升性能

所有版本记录:
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次迭代后, 连一个注册用户都已经超过了秒的单位.

提升性能

set list
add append
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放信息

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章