Python中的程序,进程,线程

程序和进程

使用multiprocessing创建线程

'''
程序:英文单词为Program,是指一系列有序指令的集合,使用编程语言所编写,用于实现一定的功能
进程:是指启动后的程序,系统会为进程分配内存空间

创建进程的方式
第一种创建进程的语法结构:Process(group=None,target,name,args,kwargs)
参数说明:
1.group:表示分组,实际上不使用,值默认为None即可
2.target:表示子进程要执行的任务,支持函数名
3.name:表示子进程的名称
4.args:表示调用函数的位置参数,以元组的形式进行传递
5.kwargs:表示调用函数的关键字参数,以字典的形式进行传递


第二种创建进程的语法结构:
class 子进程(Process):
    pass
'''
import os
import time
from multiprocessing import Process

def test():
    print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}')
    time.sleep(1)


if __name__ == '__main__':
    print('主进程开始执行')
    lst=[]
    #创建子进程
    for i in range(5):
        p= Process(target=test)
        #启动子进程
        p.start()
        #启动中的进程添加到列表中
        lst.append(p)
    #遍历列表,列表中五个子进程
    for item in lst:#item的数据类型是Process
        item.join()#阻塞主进程
    print('主进程执行结束')
    #主进程要等到所有的子进程执行完毕之后,主进程才会执行结束

Process类的属性和方法

import os
import time
from multiprocessing import Process
'''
Process常用方法/属性
方法/属性名称:            功能描述
name:                   当前进程实例别名,默认为Process-N
pid:                    当前进程对象的PID值
is_alive():             进程是否执行完,没执行完结果为True,否则为False
join(timeout):          等待结束或等待timeout秒
start():                启动进程
run():                  如果没有指定target参数,则启动进程后,会调用父类中的run方法
terminate():            强制终止进程
'''


# 函数式方式创建子进程
def sub_process(name):
    print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}----------------------------{name}')


def sub_process2(name):
    print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}----------------------------{name}')


if __name__ == '__main__':
    # 主进程

    for i in range(5):
        # 创建第一个子进程
        p1 = Process(target=sub_process, args=('ll',))
        p2 = Process(target=sub_process2, args=(18,))
        p1.start()
        p2.start()


        print(p1.name, 'pid是:', p1.pid)
        print(p2.name, 'pid是:', p2.pid)

        p1.join()  # 主进程要等p1执行结束,阻塞主进程
        p2.join()  # 主进程要等p2执行结束,阻塞主进程

        print(p1.name, '是否执行完毕', p1.is_alive())
        print(p2.name, '是否执行完毕', p2.is_alive())

    print('父进程执行完毕')
import os
import time
from multiprocessing import Process
'''
Process常用方法/属性
方法/属性名称:            功能描述
name:                   当前进程实例别名,默认为Process-N
pid:                    当前进程对象的PID值
is_alive():             进程是否执行完,没执行完结果为True,否则为False
join(timeout):          等待结束或等待timeout秒
start():                启动进程
run():                  如果没有指定target参数,则启动进程后,会调用父类中的run方法
terminate():            强制终止进程
'''


# 函数式方式创建子进程
def sub_process(name):
    print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}----------------------------{name}')


def sub_process2(name):
    print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}----------------------------{name}')


if __name__ == '__main__':
    # 主进程
    print('父进程执行开始')

    for i in range(5):
        # 创建第一个子进程
        p1 = Process(target=sub_process,args=('LL',))#没有指定target参数,不会执行自己编写的函数中的代码,会调用Precess类中的run方法
        p2 = Process(target=sub_process2,args=(18,))
        p1.start()#如果Process类创建的时候没有指定target参数调用Precess类中的run方法
        p2.start()#如果Process类创建的时候指定了target参数 start()调用target指定的函数去执行


        # print(p1.name, 'pid是:', p1.pid)
        # print(p2.name, 'pid是:', p2.pid)
        #
        # p1.join()  # 主进程要等p1执行结束,阻塞主进程
        # p2.join()  # 主进程要等p2执行结束,阻塞主进程
        #
        # print(p1.name, '是否执行完毕', p1.is_alive())
        # print(p2.name, '是否执行完毕', p2.is_alive())
        #终止进程
        p1.terminate()
        p2.terminate()

    print('父进程执行完毕')
'''
Process常用方法/属性
方法/属性名称:            功能描述
name:                   当前进程实例别名,默认为Process-N
pid:                    当前进程对象的PID值
is_alive():             进程是否执行完,没执行完结果为True,否则为False
join(timeout):          等待结束或等待timeout秒
start():                启动进程
run():                  如果没有指定target参数,则启动进程后,会调用父类中的run方法
terminate():            强制终止进程
'''
import os
import time
from multiprocessing import Process
#自定义一个类
class SubProcess(Process):
    #编写一个初始化方法
    def __init__(self,name):
        super().__init__()
        self.name = name

    #重写父类中的run方法
    def run(self):
        print(f'我是子进程,我的PIP是:{os.getpid()},我的父进程是:{os.getppid()}----------------------------{self.name}')

if __name__ == '__main__':
    print('父进程开始执行')
    lst=[]
    for i in range(1,6):
        p1 = SubProcess(f'进程:{i}')
        p1.start()
        lst.append(p1)
    for item in lst:
        item.join()

    print('主进程执行结束')

进程池

非阻塞

'''
Pool进程池
进程池原理:创建一个进程池,并设置进程池最大的进程数量,假设进程池中最大的进程数为3,现在有10个任务需要执行,那么进程池一次可以执行3个任务,4次即可完成全部人物的执行
语法结构: 进程池对象 = Pool(N)
方法名:                                    功能描述
apply_async(func,args,kwargs):          使用非阻塞方式调用函数func
apply(func,args,kwargs):                使用阻塞方式调用函数func
close():                                关闭进程池,不再接受新的任务
terminate():                            不管任务是否完成,立即终止
join():                                 阻塞主进程,必须在terminate()或close()之后使用
'''

from multiprocessing import Pool
import time, os


# 编写任务
def task(name):
    print(f'子进程的PID: {os.getpid()},执行的任务: {name}')
    time.sleep(1)


if __name__ == '__main__':
    # 主进程
    start = time.time()
    print('主进程开始执行')
    #创建进程池
    p=Pool(3)
    #创建任务
    for i in range(10):
        #以非阻塞的方式
        p.apply_async(func=task,args=(i,))

    p.close()#关闭进程池不再接受新任务
    p.join()#阻塞父进程,等待所有的子进程执行完毕后,才会执行父进程中的代码
    print('所有的子进程执行完毕,父进程执行结束')
    print(time.time()-start)

阻塞

'''
Pool进程池
进程池原理:创建一个进程池,并设置进程池最大的进程数量,假设进程池中最大的进程数为3,现在有10个任务需要执行,那么进程池一次可以执行3个任务,4次即可完成全部人物的执行
语法结构: 进程池对象 = Pool(N)
方法名:                                    功能描述
apply_async(func,args,kwargs):          使用非阻塞方式调用函数func
apply(func,args,kwargs):                使用阻塞方式调用函数func
close():                                关闭进程池,不再接受新的任务
terminate():                            不管任务是否完成,立即终止
join():                                 阻塞主进程,必须在terminate()或close()之后使用

'''

from multiprocessing import Pool
import time, os


# 编写任务
def task(name):
    print(f'子进程的PID: {os.getpid()},执行的任务: {name}')
    time.sleep(1)


if __name__ == '__main__':
    # 主进程
    start = time.time()
    print('主进程开始执行')
    #创建进程池
    p=Pool(3)
    #创建任务
    for i in range(10):
        #以阻塞的方式
        p.apply(func=task,args=(i,))

    p.close()#关闭进程池不再接受新任务
    p.join()#阻塞父进程,等待所有的子进程执行完毕后,才会执行父进程中的代码
    print('所有的子进程执行完毕,父进程执行结束')
    print(time.time()-start)

进程间数据共享

  • 进程间数据共享
'''
并发和并行
并发:是指两个或多个事件同一时间间隔发生,多个任务被交替乱换着执行,比如A事件是吃苹果,在吃苹果的过程中有快递员敲门让你手下快递,收快递是B事件,那么收完快递继续吃没吃完的苹果就是并发
并行:指两个或多个事件在同一时刻发生,多个任务在同一时刻在多个处理器上同时执行,比如A事件是泡脚,B事件是打电话,C事件是记录电话内容,这三件事则可以在同一时刻发生,这就是并行


进程之间的通信
进程之间可以通过队列(Queue)进行通信,队列是一种先进先出(First In First Out)的数据结构
创建队列的语法结构:队列对象=Queue(N)
队列常用的方法:
方法名称:                   功能描述
qsize():                获取当前队列包含的消息数量
empty():                判断队列是否为空,为空结果返回Ture,狗则为False
full():                 判断队列是否慢了,满结果为Ture,狗则为False
get(block=True):        获取队列中的一条消息,然后从队列中移除,block默认值为True
get_nowait():           相当于get(block=False),消息队列为空时,抛出异常
put(item.block=True):   将item消息放入队列,block默认值为True
put_nowait(item):       相当于put(item.block=False)
'''

from multiprocessing import Pool, Process
import time, os

a = 100


def add():
    print('子进程1开始执行')
    global a
    a += 30
    print(f'子进程1 a=: {a}')
    print('进程1执行完毕')


def sub():
    print('子进程2开始执行')
    global a
    a -= 50
    print(f'子进程2 a=: {a}')
    print('进程2执行完毕')


if __name__ == '__main__':
    # 父进程
    print(f'父进程开始执行a=: {a}')
    # 创建加法的子进程
    p1 = Process(target=add)
    # 创建剑法的子进程
    p2 = Process(target=sub)

    # 启动子进程
    p1.start()
    p2.start()
    # 阻塞主进程
    p1.join()
    p2.join()
    print(f'父进程执行结束a=: {a}')
  • 队列的基本使用
'''
并发和并行
并发:是指两个或多个事件同一时间间隔发生,多个任务被交替乱换着执行,比如A事件是吃苹果,在吃苹果的过程中有快递员敲门让你手下快递,收快递是B事件,那么收完快递继续吃没吃完的苹果就是并发
并行:指两个或多个事件在同一时刻发生,多个任务在同一时刻在多个处理器上同时执行,比如A事件是泡脚,B事件是打电话,C事件是记录电话内容,这三件事则可以在同一时刻发生,这就是并行


进程之间的通信
进程之间可以通过队列(Queue)进行通信,队列是一种先进先出(First In First Out)的数据结构
创建队列的语法结构:队列对象=Queue(N)
队列常用的方法:
方法名称:                   功能描述
qsize():                获取当前队列包含的消息数量
empty():                判断队列是否为空,为空结果返回Ture,狗则为False
full():                 判断队列是否慢了,满结果为Ture,狗则为False
get(block=True):        获取队列中的一条消息,然后从队列中移除,block默认值为True
get_nowait():           相当于get(block=False),消息队列为空时,抛出异常
put(item.block=True):   将item消息放入队列,block默认值为True
put_nowait(item):       相当于put(item.block=False)
'''

from multiprocessing import Queue

if __name__ == '__main__':
    # 创建队列
    q = Queue(3)  # 最多可以接收三条信息
    print('队列是否为空:', q.empty())  # True
    print('队列是否已满:', q.full())  # False
    # 向队列中添加信息
    q.put('hello')
    q.put('world')
    print('队列是否为空:', q.empty())  # False
    print('队列是否已满:', q.full())  # False
    q.put('Python')
    print('队列是否为空:', q.empty())  # False
    print('队列是否已满:', q.full())  # True
    print('队列当中的信息的个数:', q.qsize())  # 3

    #出队
    print('出队:',q.get())
    print('队列当中的信息的个数:', q.qsize())  # 2
    #入队
    q.put_nowait('html')
    # q.put_nowait('sql')#抛出异常  queue.Full
    # q.put('sql') #不报错,但是会一直等待,等到队列中有空位置为止
    #遍历
    if not q.empty():
        for i in range(q.qsize()):
            print(q.get_nowait())
    print('队列是否为空:', q.empty())  # True
    print('队列是否已满:', q.full())  # False
    print('队列当中的信息的个数:', q.qsize())  # 0
  • 队列中添加数据
'''
队列常用的方法:
方法名称:                   功能描述
qsize():                获取当前队列包含的消息数量
empty():                判断队列是否为空,为空结果返回Ture,狗则为False
full():                 判断队列是否慢了,满结果为Ture,狗则为False
get(block=True):        获取队列中的一条消息,然后从队列中移除,block默认值为True
get_nowait():           相当于get(block=False),消息队列为空时,抛出异常
put(item.block=True):   将item消息放入队列,block默认值为True
put_nowait(item):       相当于put(item.block=False)
'''

from multiprocessing import Queue

if __name__ == '__main__':
    # 创建队列
    q = Queue(3)  # 最多可以接收三条信息
    # 向队列中添加信息 入队
    q.put('hello')
    q.put('world')
    q.put('Python')
    # 队列已满,此时再次put数据,会一直等待
    # q.put('html')
     # 队列已满,此时再次put数据,会一直等待===>修改put的timeout参数
    q.put('html',block=True,timeout=2)#等待2秒后超时,抛出异常
    
  • 使用队列实现进程之间的通信
'''
并发和并行
并发:是指两个或多个事件同一时间间隔发生,多个任务被交替乱换着执行,比如A事件是吃苹果,在吃苹果的过程中有快递员敲门让你手下快递,收快递是B事件,那么收完快递继续吃没吃完的苹果就是并发
并行:指两个或多个事件在同一时刻发生,多个任务在同一时刻在多个处理器上同时执行,比如A事件是泡脚,B事件是打电话,C事件是记录电话内容,这三件事则可以在同一时刻发生,这就是并行


进程之间的通信
进程之间可以通过队列(Queue)进行通信,队列是一种先进先出(First In First Out)的数据结构
创建队列的语法结构:队列对象=Queue(N)
队列常用的方法:
方法名称:                   功能描述
qsize():                获取当前队列包含的消息数量
empty():                判断队列是否为空,为空结果返回Ture,狗则为False
full():                 判断队列是否慢了,满结果为Ture,狗则为False
get(block=True):        获取队列中的一条消息,然后从队列中移除,block默认值为True
get_nowait():           相当于get(block=False),消息队列为空时,抛出异常
put(item.block=True):   将item消息放入队列,block默认值为True
put_nowait(item):       相当于put(item.block=False)
'''

from multiprocessing import Queue, Process
import time

a = 100


def write_msg(q):  # q:队列
    global a
    if not q.full():
        for i in range(6):
            a -= 10
            q.put(a)  # 入队
            print('a入队时的值:', a)


# 出队
def read_msg(q):
    time.sleep(1)
    while not q.empty():
        print('a出队时的值:', q.get())


if __name__ == '__main__':
    print('父进程开始执行')
    q = Queue()  # 由父进程创建队列,没有指定参数,说明接收的消息没有上限
    # 创建两个子进程
    p1 = Process(target=write_msg, args=(q,))
    p2 = Process(target=read_msg, args=(q,))
    # 启动子进程
    p1.start()
    p2.start()
    # 等待写的程序执行结束,再去执行主进程
    p1.join()
    p2.join()
    print('父进程执行结束')

线程

函数方式创建线程

'''
线程:
线程时CPU可调度的最小单位,被包含在进程中,是进程中时机的运作单位,一个进程中可以拥有N多个线程并发执行,而每个线程并行执行不同的任务

创建线程的方式
函数式创建线程的语法结构: t=Thread(group,target,name,args,kwargs)
参数说明:
group:创建线程对象的进程组
target:创建线程对象所要执行的目标函数
name:创建线程对象的名称,默认为Tread-N
args:用元组以位置参数的形式传入target对应函数的参数
kwargs::用字典以关键字参数的形式传入target对应函数的参数

使用Thread子类创建线程的操作步骤
1.自定义类集成threding模块下的Thread类
2.实现run方法
'''
import threading
from threading import Thread
import time


# 编写函数
def test():
    for i in range(3):
        time.sleep(1)
        print(f'线程:{threading.current_thread().name}正在执行{i}')


if __name__ == '__main__':
    start = time.time()
    print('主线程开始执行')

    # 线程
    lst = [Thread(target=test) for i in range(2)]

    for item in lst:
        # 启动线程
        item.start()

    for item in lst:
        item.join()

    print(f'一共耗时:{time.time() - start}')

    #三个线程并行执行的任务是什么?  主线程负责执行 main中的代码,Thread-1线程 执行三次循环,Thread-2线程 执行三次循环
#三个线程又是并发执行,谁先执行不固定

使用Thread子类创建线程

'''
线程:
线程时CPU可调度的最小单位,被包含在进程中,是进程中时机的运作单位,一个进程中可以拥有N多个线程并发执行,而每个线程并行执行不同的任务

创建线程的方式
函数式创建线程的语法结构: t=Thread(group,target,name,args,kwargs)
参数说明:
group:创建线程对象的进程组
target:创建线程对象所要执行的目标函数
name:创建线程对象的名称,默认为Tread-N
args:用元组以位置参数的形式传入target对应函数的参数
kwargs::用字典以关键字参数的形式传入target对应函数的参数

使用Thread子类创建线程的操作步骤
1.自定义类集成threding模块下的Thread类
2.实现run方法
'''
import threading
from threading import Thread
import time

class SubThread(Thread):
    def run(self):
        for i in range(3):
            time.sleep(1)
            print(f'线程:{threading.current_thread().name}正在执行{i}')

if __name__ == '__main__':
    start = time.time()
    print('主线程开始执行')

    # 线程
    lst = [SubThread() for i in range(2)]

    for item in lst:
        # 启动线程
        item.start()

    for item in lst:
        item.join()#阻塞主线程

    print(f'一共耗时:{time.time() - start}')
'''
线程之间的通信

'''

线程间数据共享

  • 线程间是否支持共享数据
from threading import Thread
a=100#定义一个全局变量

def add():
    print('加线程开始执行')
    global a
    a+=30
    print(f'加线程a的值为:{a}')
    print('加线程执行结束')
def sub():
    print('减线程开始执行')
    global a
    a -= 50
    print(f'减线程a的值为:{a}')
    print('减线程执行结束')


if __name__ == '__main__':
    print('主线程开始执行')
    print(f'--------主线程开始执行全局变量a的值:{a}')

    #线程
    add_thread = Thread(target=add)
    sub_thread = Thread(target=sub)
    #执行线程
    add_thread.start()
    sub_thread.start()
    #阻塞主线程
    add_thread.join()
    sub_thread.join()
    print('主线程执行结束')
    print(f'--------主线程执行结束全局变量a的值:{a}')
'''
线程之间是可以进行数据共享的,需要注意进程之间不会进行共享
'''
  • 线程间共享数据的安全问题
import threading
from threading import Thread
import time

ticket = 50  # 定义一个变量,表示当前存在50张票


def sale_ticket():
    global ticket
    # 每个排队窗口假设存在100个人
    for i in range(100):
        if ticket > 0:
            print(f'{threading.current_thread().name}正在出售第{ticket}张票')
            ticket -= 1
        time.sleep(1)


if __name__ == '__main__':
    for i in range(3):  # 创建三个线程,代码三个窗口
        t = Thread(target=sale_ticket)
        t.start()

  • 使用Lock锁解决线程共享数据的安全问题
import threading
from threading import Thread,Lock
import time

ticket = 50  # 定义一个变量,表示当前存在50张票
lock_obj=Lock()#创建锁对象
def sale_ticket():
    global ticket
    # 每个排队窗口假设存在100个人
    for i in range(100):
        lock_obj.acquire()#上锁
        if ticket > 0:
            print(f'{threading.current_thread().name}正在出售第{ticket}张票')
            ticket -= 1
        time.sleep(1)
        lock_obj.release()#释放锁


if __name__ == '__main__':
    for i in range(3):  # 创建三个线程,代码三个窗口
        t = Thread(target=sale_ticket)
        t.start()

'''
线程之间是可以进行数据共享的,需要注意进程之间不会进行共享,但是线程共享数据存在安全性问题

线程安全问题:
使用Lock进行解决
锁定状态:acquire()方法
非锁定状态:release()方法
'''
  • 生产者和消费者模式
'''
生产者与消费者模式
生产者与消费者模式:是线程模型中的经典问题,与编程语言无关,当程序中出现了明确的两类任务,一个任务负责生产数据,一个任务负责处理产生的数据时就可以使用该模式

Python内置模块queue中的Queue类
方法名称:功能描述
put(item):      向对类中防止数据,如果队列为满,则阻塞
get():          从队列中取走数据,如果队列为空,则阻塞
join():         如果队列不为空,则等待队列为空
task_done():    消费者从队列中取走一项数据,当队列为空时,唤醒调用join()的线程
'''
from queue import Queue
from threading import Thread
import time


# 创建一个生产者类

class Producer(Thread):
    def __init__(self, name, queue):
        Thread.__init__(self, name=name)
        self.queue = queue

    def run(self):
        for i in range(1, 6):
            print(f'{self.name}将产品{i}放入队列')
            self.queue.put(i)
            time.sleep(1)
        print('生产者完成了所有数据的存放')


# 创建一个消费者类
class Consumer(Thread):
    def __init__(self, name, queue):
        Thread.__init__(self, name=name)
        self.queue = queue

    def run(self):
        for i in range(5):
            value = self.queue.get()
            print(f'消费者线程{self.name}取出了{i}数据')
            time.sleep(1)
        print('消费者完成了所有数据的取出')


if __name__ == '__main__':
    # 创建队列
    queue = Queue()
    # 创建生产者线程
    p = Producer('Producer', queue)
    c = Consumer('Consumer', queue)
    #启动线程
    p.start()
    c.start()
    #阻塞主线程
    p.join()
    c.join()



'''
程序:是指一系列有序指令的集合
进程:启动后的程序称为进程,系统会为进程分配内存空间
创建进程语法结构:Process(group=None,target,name,args,kwargs)
进程池:当需要多个进程的时候,就可以使用进程池Pool
创建进程池的语法结构:进程池对象=Pool(N)
并发:是指两个或多个事件同一时刻间隔发生,多个任务被交替轮换着执行
并行:是指两个或多个事件在同一时刻发生,多个任务在同一时刻在多个处理器上同时执行

进程之间不存在共享数据,但可以使用队列进行通信
线程时CPU可调度的最小单位,被包含在进程中,是进程中实际的运作单位,一个进程中可以拥有N多个线程并发执行,每个线程执行不同的任务
创建线程的两种方式:函数式,继承式
同一进程内的多个线程可以共享数据,但是会存在安全性问题
使用Lock锁解决多个线程操作贡献数据的安全问题
生产者和消费者问题是线程模型中的经典问题,与编程语言无关
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值