当前位置: 首页 > article >正文

快速入门和简单理解并发编程中的并发、并行、同步、异步,并且简单实现多进程和多线程

1. 相关概念简单理解

CPU:中央处理单元,是计算机系统的核心部件,主要负责执行程序、处理任务等。

CPU核数:CPU核心数量,主要负责执行任务,单核CPU只能执行一个任务(同一时刻,只能干一件事)

进程:简单来说,就是一个正在运行的程序,相当于一个正在加工的工厂

线程:线程是进程里面的,也就相当于工厂里面的工人

并行:同一时间,同时执行多个应用程序,多个cpu才能实现并行

并发:伪并行,看似是同时执行的,但实则是cpu内部以很快的速度不断切换执行程序

小例子区分并行和并发:

什么都不是:上完厕所,再吃饭

并行:边上厕所边吃饭

并发:上厕所的时候,吃两口饭,再继续上厕所

接下来是同步和异步:

同步:CPU在执行程序的时候,任务的每一个步骤都是按照顺序执行的,执行下一个之前,前面的必须要先执行完

异步:CPU在执行程序的时候,任务的每一个步骤都是按照顺序执行的,但是不管你是否执行完上面的程序,都会马上往下面继续执行

2. 进程

了解基本概念之后,我们来看进程相关的点

每执行的一个任务都算做一个进程,比如打开了qq音乐,打开了永劫无间,这两个都是不同的进程。

但是现在就有一个问题:早期的CPU是单核的,那么在执行程序的时候,也能边打游戏,边听音乐?

这主要是因为在操作系统内部有一种进程调度算法:“时间片轮转法”

简单来说,就是会给每个应用分配一个时间片,然后CPU交替执行多个进程,由于速度非常快,所以根本感觉不到是在交替执行

2.1 进程的实现

2.1.1 普通进程

了解了进程之后,我们来看看Python中是如何实现进程,并且实现多进程的。

import time
from multiprocessing import Process


def func():
    print('正在执行任务 ................')
    time.sleep(2)
    print('任务执行结束')


if __name__ == '__main__':
    start = time.time()
    p = Process(target=func)
    p.start()
    print('主线程执行结束', '执行时间:', time.time() - start)

我们这里用到的是multiprocessing包下面的Process模块,主要用于创建进程

target:传入需要执行的任务(函数),不需要打括号

p.start():开始执行这个进程

但是有时候,我们需要传入参数:

import time
from multiprocessing import Process


def func(a , b):
    print('正在执行任务 ................')
    time.sleep(2)
    print('任务执行结束' , a + b)


if __name__ == '__main__':
    start = time.time()
    p = Process(target=func , args=(1 , 2))
    p.start()
    print('主线程执行结束', '执行时间:', time.time() - start)

2.1.2 多进程实现异步

import time
from multiprocessing import Process


def func(name):
    print('正在执行任务 ................')
    time.sleep(2)
    print('我正在看', name)


if __name__ == '__main__':
    start = time.time()
    lst = ['完美世界', '斗破苍穹', '吞噬星空']
    for i in lst:
        p = Process(target=func, args=(i , ))
        p.start()
    print('主线程执行结束', '执行时间:', time.time() - start)

2.1.3 等待进程结束

在每次创建一个进程的时候,都是创建一个子进程

而我们发现,每次我们主进程都执行完了,而子进程还在进行

这个时候,如果我们想让子进程执行完,在执行主进程,我们该 如何去做呢?

import time
from multiprocessing import Process


def func(name):
    print('正在执行任务 ................')
    time.sleep(2)
    print('我正在看', name)


if __name__ == '__main__':
    start = time.time()
    lst = ['完美世界', '斗破苍穹', '吞噬星空']
    p_lst = []
    for i in lst:
        p = Process(target=func, args=(i , ))
        p.start()
        p_lst.append(p)

    for i in p_lst:
        p.join()
    print('主线程执行结束', '执行时间:', time.time() - start)

这里我们用到了join方法:

join方法是子进程必须要执行的方法,没有执行的时候,会产生阻塞,可以达到主进程等待子进程执行完的效果。

2.1.4 进程数据隔离

当我们想要在子进程中修改主进程的数据时,我们会发现一个现象

import time
from multiprocessing import Process

num = 10

def func():
    global num
    num = 0
    print('正在执行任务 ................')
    time.sleep(2)
    print('执行结束')


if __name__ == '__main__':
    start = time.time()
    p = Process(target=func)
    p.start()
    p.join()
    print('num' , num)
    print('主线程执行结束', '执行时间:', time.time() - start)

我们会发现,此时的全局变量num并没有被成功修改

这是因为进程之间都是数据隔离的,并不共享,就跟两个工厂之间,互不影响。

 2.1.5 守护进程

如果我们想主进程结束的时候,让子进程也结束,那么这个时候,我们该如何做呢?

这时,我们需要守护进程:

import time
from multiprocessing import Process

num = 10

def func():
    global num
    num = 0
    print('正在执行任务 ................')
    time.sleep(2)
    print('执行结束')


if __name__ == '__main__':
    start = time.time()
    p = Process(target=func)
    p.daemon = True   # 必须放在start前面
    p.start()

    print('num' , num)
    print('主线程执行结束', '执行时间:', time.time() - start)

3. 线程

线程是操作系统能够进行运算调度的最小单位,如果说进程是一个工厂,那么线程就是工厂里面的一个工人。

与进程不相同的是:

1. 同一个进程里面多个线程是共享该进程的资源的,比如一个工厂里面的工人都会经过同一个门。

2. 每一个进程中都会有一个线程,这个线程叫做“主线程”

3.1 实现线程

3.1.1 普通线程

创建线程用的是Threading模块:

from threading import Thread
def func(num):
    print('num的值是:',num)

if __name__ == '__main__':

    t = Thread(target=func,args=(1,))
    t.start()

3.1.2 多线程实现异步

import time
from threading import Thread

start = time.time()
def get_requests(url):
    print('正在获取数据')
    time.sleep(2)
    print('获取结束')

urls = ['1','2','3','4','5']

for url in urls:
    t = Thread(target=get_requests,args=(url,))
    t.start()

print('总耗时:',time.time()-start)

其实大部分思路和进程一样。

 3.1.3 等待线程结束

import time
from threading import Thread

start = time.time()
def get_requests(url):
    print('正在获取数据')
    time.sleep(2)
    print('获取结束')

urls = ['1','2','3','4','5']
ts = []
for url in urls:
    t = Thread(target=get_requests,args=(url,))
    t.start()
    ts.append(t)
for t in ts:
    t.join()

print('总耗时:',time.time()-start)

3.1.4 线程数据共享

from threading import Thread

import time
def work():
    global n
    n = 0 #将全局变量修改为了0

if __name__ == '__main__':
    n = 1 #全局变量
    t = Thread(target=work)
    t.start()
    print(n) #结果为0

3.1.5 守护线程

from threading import Thread

import time
def work():
    time.sleep(1)
    print('子线程正在执行!')

if __name__ == '__main__':
    t = Thread(target=work)
    t.daemon = True # 必须放在start之前
    t.start()
    print('主线程结束!')

3.2. 线程池

from multiprocessing.dummy import Pool #导入了线程池模块
import time
urls = ['1','2','3m']
def get_reqeust(url):
    print('正在请求数据:',url)
    time.sleep(2)
    print('请求结束:',url)

start = time.time()
#创建一个线程池,开启了5个线程
pool = Pool(5)

#可以利用线程池中三个线程不断的去处理任务
pool.map(get_reqeust,urls)

print('总耗时:',time.time()-start)
pool.close() #释放线程池

4. 总结

本篇文章快速入门了关于异步编程的一些基本概念和实现,但是还有很多高级内容本文并未提及:锁机制、协程等


http://www.kler.cn/a/302294.html

相关文章:

  • 基于Spring Boot的计算机课程管理:工程认证的实践
  • 项目技术栈-解决方案-web3去中心化
  • mysql 配置文件 my.cnf 增加 lower_case_table_names = 1 服务启动不了的原因
  • Ubuntu 的 ROS 操作系统安装与测试
  • docker构建jdk11
  • HBase 安装与基本操作指南
  • JS设计模式之代理模式:对象的“虚拟与现实”
  • 基于51单片机的灯盘检测(PCF8591+CD4051 )
  • mp3转文字要怎么处理?使用这4个工具就对了
  • C# 中的矢量化运算:提升性能的艺术
  • OpenHarmony鸿蒙开发( Beta5.0)智能窗帘应该开发实践案例
  • 算法刷题[比较两个字符串的最大公字符串(滑动窗口实现)]
  • 基于Boost库的搜索引擎开发实践
  • OpenFeign原理
  • docker-ce.repo源、kubernetes.repo源
  • 通过AI来创建一个_____html css网页制作成品 例子演示
  • 精准电商营销:基于京东商品详情API返回值的数据分析
  • 探索Python中的链式赋值、系列解包赋值与常量
  • Vue.js中computed的使用方法
  • Minio笔记-Centos搭建Minio
  • pgAdmin 4备份数据库失败,解决
  • 武汉墨家人俱乐部
  • 计算机毕业设计选题推荐-校园车辆管理系统-Java/Python项目实战(亮点:数据可视化分析、账号锁定)
  • 如何为 MongoDB 3.0.4 以下版本选择合适的 PyMongo 版本
  • 第10章 中断和动态时钟显示
  • 零基础5分钟上手亚马逊云科技-为网站服务器配置DNS域名