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

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. 总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jiaoxingk

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

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

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

打赏作者

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

抵扣说明:

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

余额充值