python 后端

协程,线程,进程

进程

进程打开一个浏览器就是,就是启动了一个浏览器进程。一个运行的程序(代码)就是一个进程,没有运行的代码叫程序。进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。进程是执行任务的基本单元,也是操作系统执行任务的基本单元。进程中包含了程序指令和相关资源的集合。进程互不影响,可以同时执行,如果你是多核cpu
创建进程: 一般通过进程池

线程

在一个进程中,至少有一个线程,这个线程就是当前进程的主线程,
线程是进程中执行任务的基本单元,线程不能独立存在,依赖进程存在而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
多线程执行任务会出现数据混乱的问题甚至是死锁。不能同时执行,只能切换执行。
一般通过线程池

import concurrent.futures

def root():
    with concurrent.futures.ThreadPoolExecutor() as executor:
    # 执行urls的长度的线程
        response = executor.map(fetch_data, urls)
    return list(response)

def fetch_data(url):
    # 通过url获取数据的代码
    return data

协程

通过 async await 创建一个协程,和线程一样不能同时执行只能切换执行

async def root():
    response = await asyncio.gather(
        fetch_data(),
        process_data()
    )
    return response

async def fetch_data():
    async with aiohttp.ClientSession() as session:
        response = await session.get("https://api.example.com")
        return await response.json()

async def process_data():
    # 处理数据的代码
    return processed_data

三者对比

全局解释器锁(GIL):
多线程: 在Python中,由于全局解释器锁(GIL)的存在,即使在多线程环境下,CPython解释器在任何给定时间只允许一个线程执行Python字节码,只能执行一个。因此,对于计算密集型任务,多线程可能不会带来性能提升,因为线程们在执行计算时会相互阻塞。但对于IO密集型任务,由于IO操作(如文件读写、网络请求等)不受GIL影响,多线程可以在一个线程等待IO时执行其他线程,从而提高效率。
多进程: 每个进程有自己的内存空间和解释器,因此不受GIL的限制。这意味着在多核处理器上,多个进程可以真正并行执行计算密集型任务。每个进程都独立运行,所以它们不会像线程那样共享内存或数据。
资源消耗和通信开销:

多线程: 线程通常比进程消耗更少的资源。线程共享相同的内存空间,因此在线程间共享数据相对容易且开销较小。
多进程: 进程之间不共享内存,每个进程都有自己的内存空间。这意味着进程之间的通信(比如使用队列或管道)更复杂且开销更大。同时,创建进程的开销也比创建线程大。
适用场景:

多线程: 适合于IO密集型任务,如文件操作、网络通信等。
多进程: 更适合于计算密集型任务,尤其是在多核处理器上。
稳定性:

多线程: 一个线程崩溃可能会影响整个程序的稳定性。
多进程: 一个进程崩溃不会直接影响其他进程

Python中的WebSocket编程

我暂时还用到,可以考虑借鉴下面这篇
https://zhuanlan.zhihu.com/p/630520426
Chrome 浏览器中查看 webSocket 连接信息
https://www.cnblogs.com/zhuyeshen/p/12007217.html
通过 Chrome浏览器 查看http请求报文
https://www.cnblogs.com/loberty/p/11990576.html
https://blog.csdn.net/ytangdigl/article/details/73135466#

日志

主要了解一些必要的知识,以及部署后端接口的工程上要用到的知识,不会讲太细太全,一些知识需要自己去问gpt。

logging

日志基本设置输出,输出格式,输出目标文件

import logging
#设置输出到那个文件,什么级别以上的日志会被记录logging.ERROR)以上的
logging.basicConfig(filename='log.txt',
format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s-%(funcName)s',
                     level=logging.ERROR)
                     #下面的按顺序越来越高
logging.debug('debug,用来打印一些调试信息,级别最低')
    logging.info('info,用来打印一些正常的操作信息')
    logging.warning('waring,用来用来打印警告信息')
    logging.error('error,一般用来打印一些错误信息')
    logging.critical('critical,用来打印一些致命的错误信息,等级最高')
    

只有一个文件可能会这样用

日志记录器(Logger)

logger = logging.getLogger(name)
#name通常是使用__name__变量,以确保日志记录器在整个应用中的唯一性

这样输出到日志中会带有你的当前的模块,不同的模块在日志中就会显示出来
也可以设置日志基本设置,这个的优先级会比较高,如果没有设置就会继承他

logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

默认记录器: 如果没有指定名称,getLogger()函数返回的是root记录器。这在你只需要一个简单的日志记录系统时非常方便。
继承行为: 在logging的层次结构中,如果一个具体的记录器(由getLogger(name)返回)没有明确设置日志级别或处理器,它将继承root记录器的配置。
日志基本设置 也是用root记录器

处理器(Handlers):

用于确定日志的目的地,如文件、控制台。
常见的处理器包括StreamHandler(控制台输出),FileHandler(写入文件),RotatingFileHandler(日志滚动),

FileHandler

handler = logging.FileHandler(‘myapp.log’, ‘a’),这里’a’表示以追加模式打开文件
设置日志级别(可选):

你可以为FileHandler设置一个特定的日志级别,以过滤掉低于此级别的日志消息。
例如:handler.setLevel(logging.INFO)。
创建并设置Formatter(可选):

Formatter决定了日志消息的最终输出格式。你可以创建一个Formatter对象,并将其添加到FileHandler。
例如:formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’),
然后使用handler.setFormatter(formatter)。
将创建的FileHandler添加到一个Logger对象
logger.addHandler(handler)。一般会考虑添加到root里面

设置自动按年月日保存
import os
import logging
from datetime import datetime

class CustomDailyFileHandler(logging.FileHandler):
    # 初始化函数
    def __init__(self, log_directory, mode='a', encoding=None, delay=False):
        # 基本配置
        self.log_directory = log_directory  # 日志文件的根目录
        self.mode = mode  # 文件打开模式,默认为追加模式
        self.encoding = encoding  # 文件编码
        self.delay = delay  # 是否延迟打开文件
        self.current_date = None  # 当前日志文件的日期
        self.update_file_path()  # 更新日志文件路径

        # 调用父类的初始化方法
        super().__init__(self.file_path, self.mode, self.encoding, self.delay)

    # 更新日志文件路径
    def update_file_path(self):
        current_date = datetime.now()
        # 创建年、月、日目录
        year_dir = os.path.join(self.log_directory, str(current_date.year))
        month_dir = os.path.join(year_dir, str(current_date.month))
        day_dir = os.path.join(month_dir, str(current_date.day))

        # 如果目录不存在,则创建
        os.makedirs(day_dir, exist_ok=True)

        # 设置日志文件路径
        self.file_path = os.path.join(day_dir, f"log_{current_date.strftime('%Y-%m-%d')}.log")
        self.current_date = current_date.strftime('%Y-%m-%d')

    # 重写 emit 方法,用于日志记录
    def emit(self, record):
        # 如果日期变更,更新文件路径
        if datetime.now().strftime('%Y-%m-%d') != self.current_date:
            self.update_file_path()
            # 关闭当前文件流,并重新打开新的日志文件
            self.stream.close()
            self.stream = open(self.file_path, self.mode, encoding=self.encoding)

        # 调用父类的 emit 方法记录日志
        super().emit(record)

       
def setup_logging():
    log_directory = 'log'
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler = CustomDailyFileHandler(log_directory)
    handler.setFormatter(formatter)

    logger.addHandler(handler)

如果你是用gunicorn去记录日志的话,
import logging
logger = logging.getLogger(“gunicorn.error”) 通过这个就可以写到gunicorn的日志文件里面了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值