聊聊并发编程

🎬 博客主页:楼下安同学的博客

🎥 本文由 楼下安同学 原创 🙉

🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

📆生活明朗,万物可爱,人间值得,未来可期!✨

----❤️-----❤️-----❤️-----❤️-----❤️-----❤️-----❤️-----

浅析

  在当今互联网的时代,大量的互联网应用都面对着海量的访问请求,因此,并发编程在我们的应用中成为越来越不可或缺的一部分,这也是互联网行业的一大趋势,更是技术的革命。对于程序员来说,也是一项挑战,使用并发编程写的代码可读性并不是很高,但我们也不能停止前进的脚步。

什么是高并发

  高并发(High Concurrency)是一种系统运行过程中遇到的一种短时间内遇到大量操作请求的情况,主要发生在web系统集中大量访问收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。

高并发的处理指标

高并发相关常用的一些指标有:

1.响应时间(Response Time)

​ 系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间

2. 吞吐量(Throughput)

​ 吞吐量:单位时间内处理的请求数量。

3. 每秒查询率QPS(Query Per Second)

​ QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。

4.并发用户数

​ 同时承载正常使用系统功能的用户数量。

高并发技术方案

  1. 分布式缓存:redis、mongo等。
  2. 消息队列中间件:解决大量消息的异步处理能力。
  3. 应用拆分: 一个工程被拆分为多个工程部署。
  4. 数据库垂直拆分和水平拆分(分库分表)等。
  5. 数据库读写分离,解决大数据的查询问题。
  6. 还可以利用nosql ,例如Redis配合mysql组合使用。
  7. 建立大数据访问情况下的服务降级以及限流机制等。

多进程

  进程Process:进程是操作系统进行资源分配的基本单位,一台机器上可以有多个进程,每个进程执行不同的程序,每个进程相对独立,拥有自己的内存空间,隔离性和稳定性比较高,进程之间互不影响,但是资源共享相对麻烦,系统资源占用相对高,同时进程可以利用cpu多核资源,适合cpm密集型任务,比如一些统计计算任务,比如计算广告转化率,uv、pv等等,或者一些视频的压缩解码任务,进程还有一个使用场景,就是后期部署项目的时候,nginx反向代理后端服务,往往需要开启多个tornado服务来支持后台的并发,就是利用了多进程的互不干扰,就算某个进程僵死,也不会影响其他进程,进程使用的是mulitprossing库 ,往往是先声明进程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定进程数的容器中(list),通过循环或者列表推导式,使用start方法开启进程,join方法阻塞主进程。

多进程简单实现

from multiprocessing import Process, Lock  # 多进程
import time

lock = Lock()

def worker(val):
    with lock:
        time.sleep(1)
        print("执行进程%s号" % val)


if __name__ == "__main__":
    # 声明进程数量
    plist = [Process(target=worker, args=(x,)) for x in range(10)]

    [i.start() for i in plist]  # 执行多进程
    [i.join() for i in plist]  # 阻塞主进程

多线程

  线程thread:线程是操作系统进行资源调度的最小单位,它属于进程,每一个进程中都会有一个线程,由于线程操作是单进程的,所以线程之间可以共享内存变量,互相通信非常方便,它的系统开销比进程小,它是线程之间由于共享内存,会互相影响,如果一个线程僵死会影响其他线程,隔离性和稳定性不如进程,同时,线程并不安全,如果对同一个对象进行操作,需要手动加锁,另外从性能上讲,多线程会触发python的全局解释器锁,导致同一时间点只会有一个线程运行的交替运行模式,线程适用于io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务,比如我负责开发的审核系统,需要同时对mysql和redis有大量的读写操作,所以我使用多线程进行消费。线程使用的是Threading库 ,往往是先声明线程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定线程数的容器中(list),通过循环或者列表推导式,使用start方法开启线程,join方法阻塞主线程。

多线程的简单使用

import threading
import time

lock = threading.Lock()	# 线程锁


# 执行方法
def worker():
    with lock:
        time.sleep(1)
        print("执行方法worker")

# 创建线程对象
threads = [threading.Thread(target=worker) for _ in range(10)]

if __name__ == "__main__":
    [t.start() for t in threads]  # 执行线程启动方法
    [t.join() for t in threads]  # 阻塞主线程

协程

  协程:是一种用户态的轻量级线程,协程的调度完全由用户控制,不像进程和线程是系统态,所以操作全局变量的时候,无需加锁,只需要判断资源状态即可,效率非常高,同时协程是单线程的,即可以共享内存,又不需要系统态的线程切换,同时也不会触发gil全局解释器锁,所以它性能比线程要高。具体使用场景和线程一样,适合io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务,比如我负责开发的审核系统,需要同时对mysql和redis有大量的读写操作,所以我后期将多线程改造成协程进行消费。协程我使用的python原生协程库asyncio库,首先通过asyncio.ensure_future(doout(4))方法建立协程对象,然后根据当天审核员数量指定开启协程数,和多线程以及多进程的区别是,协程既可以直接传实参,也可以传不定长参数,很方便,然后通过await asyncio.gather(*tasks)方法启动协程,需要注意的是,主方法需要声明成async方法,并且通过asyncio.run(main())来启动。协程虽然是python异步编程的最佳方式,但是我认为它也有缺点,那就是异步写法导致代码可读性下降,同时对编程人员的综合素质要求高,并不是所有人都能理解协程的工作方式,以及python原生协程的异步写法。

简单实现协程

import asyncio
import time


# 需要执行的任务
async def task(val):
    time.sleep(1)
    print(val)


# 执行的方法
async def main():
    tasks = [asyncio.create_task(task(i)) for i in range(10)]  # 建立协程对象
    await asyncio.gather(*tasks)  # 异步执行


if __name__ == "__main__":
    asyncio.run(main())  # 通过协程库执行任务

小结

  并发编程是未来发展的一大趋势,但是并发编程的代码可读性并不是很高,尤其是我们要结合实际开发情况使用异步编程提高效率,再结合web框架使用,这还是很难得,但还得从0开始掌握好基础,见得多了也就熟悉了!
在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楼下安同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值