前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python 数据库性能提升 - TCP聊天+传输文件服务器服务器套接字v2.7

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

作者头像
zmh-program
发布2023-02-06 10:12:47
7180
发布2023-02-06 10:12:47
举报
文章被收录于专栏:信息技术博客

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)

代码语言:javascript
复制
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,

代码语言:javascript
复制
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)
代码语言:javascript
复制
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

代码语言:javascript
复制
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放信息

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-06-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 测试
  • 提升性能
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档