线程丶进程丶协程(二)进程

                                           进程

同步:

 多任务, 多个任务之间执行的时候要求有先后顺序,必须一个先执行完成之后,

另一个才能继续执行, 只有一个主线

异步,指的是:多个任务之间执行没有先后顺序,可以同时运行,

执行的先后顺序不会有什么影响,存在的多条运行主线

对于上篇计算错误的问题,可以通过线程同步来进行解决

思路,如下:

系统调用t1,然后获取到g_num的值为0,此时上一把锁,即不允许其他线程操作g_num

t1对g_num的值进行+1

t1解锁,此时g_num的值为1,其他的线程就可以使用g_num了,而且是g_num的值不是0而是1

同理其他线程在对g_num进行修改时,都要先上锁,处理完后再解锁,在上锁的整个过程中不允许其他

线程访问,就保证了数据的正确性

互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制

某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;

直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。

互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

threading模块中定义了Lock类,可以方便的处理锁定:

# 创建锁

mutex = threading.Lock()

# 锁定

mutex.acquire()

# 释放

mutex.release()

上锁解锁过程

当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。

每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,

直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。

线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

注意:

1、互斥锁,所谓互斥就是竞争资源的多方必须:都加锁、加同一把锁 才有意义

2、一般情况下,只针对最紧迫的资源加锁(范围越小越好)

总结

锁的好处

确保了某段关键代码只能由一个线程从头到尾完整地执行

锁的坏处:

阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了

由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁。

进程概念

进程是资源分配的最小单位,程序隔离的边界。

CPU的时间片轮转,在不同的时间段切换执行不同的进程,但是切换进程是比较耗时的;就引来了轻量级进程,也就是所谓的线程,

一个进程中包括多个线程(代码流,其实也就是进程中同时跑的多个方法体)

程序:例如xxx.py这是程序,是一个静态的

进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。

 

进程的状态

工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,

因此导致了有了不同的状态

就绪态:运行的条件都已经慢去,正在等在cpu执行

执行态:cpu正在执行其功能

等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态

进程的创建-multiprocessing

 

multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情

import multiprocessing

if __name__ == '__main__':

 

    # 创建进程

    # 1. 导入 multiprocessing 模块

    # 2. multiprocessing.Process() 创建子进程

    # 3. start() 方法启动进程

    p1 = multiprocessing.Process(group=None, target=work1)

p1.start()

#进程间不共享全局变量

# 导入创建进程需要的代码
import multiprocessing
import  time

#定义函数
def work1():
    for i in range(10):
        print("---work%d----"%i)
        time.sleep(0.5)
  
        
        #打印当前进程的PID
        print("当前进程的pid",multiprocessing.current_process().pid)

if __name__ == '__main__':

    #创建进程

    t1 = multiprocessing.Process(group=None,target=work1)
    t1.start()

进程、线程对比

功能

进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ

线程,能够完成多任务,比如 一个QQ中的多个聊天窗口

定义的不同

进程是系统进行资源分配和调度的一个独立单位.

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.

线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),

但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

区别

一个程序至少有一个进程,一个进程至少有一个线程.

线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。

进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率

线程不能够独立执行,必须依存在进程中

优缺点

线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。

 Queue介绍

可以使用multiprocessing模块的Queue实现多进程之间的数据传递,

Queue本身是一个消息列队程序

 Queue基本使用

 创建队列并且放入值

说明

初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);

Queue.qsize():返回当前队列包含的消息数量;

Queue.empty():如果队列为空,返回True,反之False ;

Queue.full():如果队列满了,返回True,反之False;

Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;

如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常;

如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;

Queue.get_nowait():相当Queue.get(False);

Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;

如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常;

如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;

Queue.put_nowait(item):相当Queue.put(item, False);

消息数量、判断是否为空、判断是否已满

# 导入模块
import multiprocessing

# 定义消息队列
# 如果不指定队列长度,则默认为最大,如果指定了消息队列的大小,则消息队列就有上限控制
# 此处的 Queue(3) 指的是放入3条消息
queue = multiprocessing.Queue(3)
# queue.put(值) 向消息队列中放入内容
# put的值几乎可以是任意类型
queue.put(1)             # 放入第一个值
queue.put("hello")       # 放入第二个值
queue.put([1, 2, 3])     # 放入第三个值
# 打印队列对象
print(queue)

# 获取第一个值
value1 = queue.get()
print(value1)

# 获取第二个值
value2 = queue.get()
print(value2)

# 获取第三个值
value3 = queue.get()
print(value3)

 Queue实现进程间通信

我们以Queue为例,在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读数据:

import multiprocessing
import time


def write_queue(queue):
    # 循环写入数据
    for i in range(10):

        if queue.full():
            print("队列已满!")
            break

        # 向队列中放入消息
        queue.put(i)

        time.sleep(0.5)


def read_queue(queue):
    # 循环读取队列消息
    while True:
        # 队列为空,停止读取
        if queue.empty():
            print("---队列已空---")
            break

        # 读取消息并输出
        result = queue.get()
        print(result)


if __name__ == '__main__':

    # 创建消息队列
    queue = multiprocessing.Queue(3)

    # 创建子进程
    p1 = multiprocessing.Process(target=write_queue, args=(queue,))
    p1.start()
    # 等待p1写数据进程执行结束后,再往下执行
    p1.join()

    p1 = multiprocessing.Process(target=read_queue, args=(queue,))
    p1.start()

猜你喜欢

转载自blog.csdn.net/qq_36828513/article/details/81138080