百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

一个 Python 小项目的小结(python小型项目)

toqiye 2024-08-13 11:23 41 浏览 0 评论

段时间临时接手一个 Python 小项目,这个项目实现的类似一个管控平台,其中核心功能是为算法同学提供机器学习模型训练任务的全流程管理,平台后端基于 Flask 框架实现,前端基于 Ant Design Pro 实现。

代码稍微有些乱,所以做了部分代码的重构,在此做点经验小结。

1、并行化或异步化

部分请求处理逻辑,由于比较耗时,故使用线程池来加速,或者使用独立线程异步处理,或者先存储一个中间状态,由后台定时任务来完成实际的处理工作。对于异步处理结果,前端通过轮询来获取。

线程池的使用,主要使用 map 方法:

from multiprocessing.dummy import Pool

input_list = [...]
pool: Pool = Pool(len(input_list))
pool.map(func, input_list)
pool.close()
pool.join()

独立线程异步处理:

import multiprocessing

p = multiprocessing.Process(target=func, args=(...))
p.start()

定时任务,基于 apscheduler 库实现:

from apscheduler.schedulers.background import BackgroundScheduler

scheduler = BackgroundScheduler()

scheduler.add_join(func, 'interval', seconds=1)

scheduler.start()

因为对于 Python 应用,通常会使用 gunicorn 这种 WSGI HTTP 服务器以多进程启动多个应用实例,提升请求吞吐能力。但是对于定时任务我们希望只有一个实例,对此,如果使用 gunicorn,可以基于它的 preload 机制来实现:

# wsgi.py
import app

if __name__ == "__main__":
    app.run()
# 注意其中的 --preload 参数
gunicorn --workers=4 --preload --log-level=info --access-logfile=access.log -b 0.0.0.0:8080 wsgi:app

preload 机制简单来说,就是 import app 类所在的模块及其依赖的各个模块(import 过程中会执行其中的语句),然后 fork 出多个进程,每个进程都执行 app.run()。

2、实现一些通用方案对异常进行捕获或重试

def exception_try(times: int = 3, sleep_then_try_seconds=None):
    def decorator(f):
        def wrapper(*args, **kwargs):
            count = 0
            exception = None
            while count < times:
                try:
                    return f(*args, **kwargs)
                except Exception as e:
                    exception = e
                    count += 1
                    logging.exception("Try {} times".format(count))
                    if (sleep_then_try_seconds is not None) and count < times:
                        time.sleep(sleep_then_try_seconds)
            raise exception
        return wrapper
    return decorator
@exception_try(times=3, sleep_then_try_seconds=0.5)
def connect(self):
    return pymysql.connect(host=self.host, user=self.user, password=self.password, db=self.db, charset=self.charset)

这个装饰器方法用于实现异常重试,并且可以指定重试的时间间隔,实际使用下来效果较好。而且也不会因为 try...except 导致大块代码缩进。

确保数据库连接关闭(其它类似资源也可以这样实现)

def with_db(db: Connection, exception_callback=None):
    def decorator(f):
        def db_context(*a, **kw):
            try:
                return f(db, *a, **kw)
            except Exception as e:
                logging.exception(str(e))
                if exception_callback is not None:
                    exception_callback(e)
            finally:
                try:
                    db.close()
                except:
                    pass
        return db_context

    return decorator
# 将 conf.db.connect() 对象作为 delete_task_from_job_queue 的第一个参数注入,task_id 这个参数以不定参数的方式传入 delete_task_from_job_queue
with_db(conf.db.connect())(delete_task_from_job_queue)(task_id)

这个装饰器方法用于确保数据库连接在异常发生也能正常关闭,防止资源泄露。

3、循环等待或超时

class TimeoutCondition(object):

    def __init__(self, condition_func, timeout_seconds):
        self.condition = condition_func
        self.timeout = timeout_seconds
        self.begin = None
        self.timeout_false = True
        self.cond_true = True

    def __bool__(self):
        if self.begin is None:
            self.begin = timeit.default_timer()
        self.cond_true = self.condition()
        self.timeout_false = self.timeout <= 0 or (timeit.default_timer() - self.begin) < self.timeout
        return self.cond_true and self.timeout_false

    def is_timeout(self):
        return self.cond_true and not self.timeout_false
cond = TimeoutCondition(lambda : len(service_list) == 0, 5)
while cond:
    time.sleep(1)
    service_list = get_service_list()
if cond.is_timeout():
    return None, None

TimeoutCondition 用于实现循环等待某个条件满足,但为了避免死循环,所以加一个超时条件判断。实例化参数第一个是原始的条件判断 lambda 语句,第二个是一个超时设置。另外,借助魔术方法 __bool__ ,让 TimeoutCondtion 的实例用起来像是一个布尔变量,调用 is_timeout() 方法可以区分循环等待退出是因为原始条件满足,还是超时退出的。

4、按部署环境配置应用的行为

应用在不同的环境(开发、测试、生产)中应该允许加载不同的配置,配置不同的行为。

当前应用处于什么环境,可以通过环境变量来配置,应用初始化时最先检测当前处于什么环境,之后的初始化流程就可以依据环境配置来加载配置,定制应用行为。

# conf/__init__.py
class AppConfig(object):
    app_env = os.getenv('APP_ENV', 'development')
    is_prod = app_env == 'production'
    is_dev = app_env == 'development'
    is_testing = app_env == 'testing'

    # 其余应用配置项
    ...

conf = AppConfig()


def _load_config_by_env(env: str):
    '''
    不同环境加载不同的配置文件
    配置目录结构:
    conf/
        __init__.py
        development.py
        production.py
        testing.py
    '''
    module = importlib.import_module('conf.{}'.format(env))
    if not hasattr(module, 'Config'):
        logging.warning('Not find {} config'.format(env))
        return
    for name, value in getattr(module, 'Config').__dict__.items():
        if name.startswith('__'):
            continue
        conf.__dict__[name] = value
# 根据环境配置日志级别
log_level = logging.INFO if conf.is_prod else logging.DEBUG
logging.basicConfig(format=consts.LOG_FORMAT, level=log_level)

相关推荐

【SQL】SQL 语法差异大全(PgSQL/MySQL/Oracle/TiDB/OceanBase)

以下是针对不同数据库系统的SQL语法差异总结,按功能分类展示:一、基础查询1.分页查询--PostgreSQL/TiDB/OceanBaseSELECT*FROMTableNameL...

msf系列片之vps搭建,黑客的世界你真的了解嘛?

最后喜欢我文章的朋友请加圈子关注我们,私信关键词:学习。(送免费资料和优惠券)就会自动分享给你微信号。欢迎大家加入我们的安全大家庭。提高大家的安全意识,提升大家的网络安全技能一直是我们的初衷和愿景,让...

小技巧:ubuntu 24.04.1中自带Python升级到3.12.9和3.13.2最新版

喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。这几天一直有朋友问我,如何将ubuntu24.04.1中自带Python升级到最新版,今天就来详细讲讲。方法1:使用DeadSn...

linux下开发一个应用,首先要做什么?

作为一个linux的忠实用户,日常工作基本上不用windows系统。为什么这么说呢?word加上QQ不用不行呀。有人说LibreOffice加上Pidgen可以替代,但实际上部分word会排版不正确,...

ubuntn部署flask(flask如何部署)

1.装一下pyenvgitclonehttps://github.com/pyenv/pyenv-virtualenv.git$(pyenvroot)/plugins/pyenv-virtu...

招聘平台HireVue完成E轮融资 并推面试平台

Yesky天极新闻2015-06-0316:31:55【Yesky新闻频道消息】日前,在线视频面试的招聘服务初创企业HireVue获得4500万美元E轮融资。由TechnologyCrossove...

面试官:说一下vue2和vue3的响应式原理

Vue2的响应式原理:初始化阶段:在创建Vue实例时,遍历data对象的属性,使用Object.defineProperty方法为每个属性定义getter和setter。Getter拦截:在gett...

vue3还用this吗?getCurrentInstance获取当前组件实例

在Vue2中,this关键字代表当前组件实例。在组件的选项对象中,this可以用于访问组件实例的属性、方法以及Vue实例的一些特定方法。在Vue3中,我们发现this是undefined...

Vue.js 中的异步组件是什么?(vue.js异步请求)

本号用于每日更新前端最新面试题,React、Vue、小程序、JavaScript、HTML5、CSS、uniapp、ES6、前端工程化、性能优化等热点面试题~~~欢迎关注,面试题刷起来~~升职加薪不是...

面试官:聊聊你知道的Vue与React的区别

最近面到很多大公司的时候,小编都会碰到一个很尴尬的问题,很多大公司的技术栈都是React,但是小编学的是Vue,其实从本质上来说两者都是比较优秀的前端框架,所以有些面试官会问到Vue和React的区别...

Vue核心响应式原理深度解析!手写TodoList实战

导读:搞懂这个知识点,秒杀80%前端面试题!原理+实战+调试技巧三合一核心1:数据响应式黑科技(图解)原理示意图数据变化→依赖收集→自动更新视图Vue2vsVue3实现对...

前端面试题-原生 js 如何进行监听路由的变化?vue框架是否用到?

在原生JavaScript中监听路由变化的方式主要分为两种场景:监听哈希(Hash)路由变化和监听HistoryAPI的路由变化。Vue框架本身并不直接处理路由监听,但Vue的官方路由...

vue引入element-ui后界面空白(vue怎么引入element)

正文部分配置vue:3.0vue-cli:4.5.11目的使用element-ui绘制ui界面原本操作(1)安装element-uinpmielement-ui-S(2)导入element-ui...

前端面试-关于vue3的响应式原理(vue响应式的原理一句话概括)

现在工作不好找的环境中,想要更好获得工作机会,让我们一起准备面试题吧~Vue3的响应式系统采用ES6的Proxy实现数据劫持,与Vue2的Object.defineProperty有...

2024前端大厂面试题 Vue.js中的keep-alive组件有什么作用

小伙伴们在面试前端开发工程师的时候是不是会遇到面试官问Vue.js中的keep-alive组件有什么作用?今天我们就来告诉大家,解锁2024大厂vue面试题Vue.js中的keep-alive组件有什...

取消回复欢迎 发表评论: