进程,互斥锁,生产者消费者,线程

进程,互斥锁,生产者消费者,线程

一、僵尸进程与孤儿进程

  • 代码演示
'''
僵尸进程(有坏处):
    - 在子进程结束后,主进程没有正常结束,子进程的PID不会被回收。

    缺点:
        - 操作系统中PID号是有限的,比如子进程PID号无法正常回收,则会占用PID号。
        - 资源浪费
        - 若PID号满了,则无法创建新的进程。

孤儿进程(没有坏处):

    - 在子进程没有结束时,主进程没有“正常结束”,子进程PID不会被回收。
    - 操作系统优化机制(孤儿院):
        当主进程意外终止,操作系统会检测是否有正在运行的子进程,会将他们放入孤儿院,让操作系统帮你自动回收。

'''
#孤儿院进程
from multiprocessing import Process
from multiprocessing import current_process
#在子进程中调用,可以拿到子进程对象.pid可以获取pid号
#在主进程中调用,可以拿到主进程对象.pid可以获取pid号
import os
import time

def task():
    print(f'start...{current_process().pid}')
    time.sleep(1000)
    print(f'end...{os.getpid()}')
    print('子进程结束啦啊...')

if __name__ == '__main__':
    p = Process(target=task)

    p.start()

    print(f'进入主进程的io--->{current_process().pid}')
    time.sleep(4)
    print(f'进入主进程的io--->{os.getpid()}')

    #主进程结束
    print('主进程结束...')
    print(f'查看主进程{os.getpid()}')
    f = open('yafenghandsome.txt')#此时主进程没有正常结束

#僵尸进程
from multiprocessing import Process
from multiprocessing import current_process
#在子进程中调用,可以拿到子进程对象.pid可以获取pid号
#在主进程中调用,可以拿到主进程对象.pid可以获取pid号
import os
import time
def task():
    print(f'start...{current_process().pid}')
    time.sleep(1)
    print(f'end...{os.getpid()}')
    print('子进程结束啦啦...~~~')

if __name__ == '__main__':
    p = Process(target=task)

    p.start()

    print(f'进入主进程的io--->{current_process().pid}')
    time.sleep(5)
    print(f'进入主进程的io--->{os.getpid()}')

    print('主进程结束...')
    print(f'查看主主进程{os.getppid()}')
    f = open('yafeng6666.txt')

二、子进程回收的两种方式

  • 代码演示
from multiprocessing import Process
import time

# def task():
#     print('start...')
#     time.sleep(2)
#     print('end...')
#
#
#
# #方式一join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源。
# if __name__ == '__main__':
#     p = Process(target=task)
#
#     #告诉操作系统帮你开启子进程
#     p.start()
#     p.join()
#
#     time.sleep(3)
#
#     #主进程结束
#     print('主进程结束...')

# 方式二主进程 “正常结束” ,子进程与主进程一并被回收资源。

def task():
    print('start...')
    time.sleep(2)
    print('end...')

if __name__ == '__main__':
    p = Process(target=task)
    p.start()

    time.sleep(1)
    print('主进程结束...')

三、进程守护

  • 演示
'''
       守护进程:
            当主进程结束时,子进程也必须结束,并回收。
'''

from multiprocessing import Process

import time

def demo(name):
    print(f'start....{name}')
    time.sleep(100)
    print(f'end...{name}')
    print('子进程结束啦啊....')

if __name__ == '__main__':
    p = Process(target=demo, args=('童子军Jason1号',))

    # 守护进程必须在p.start()调用之前设置
    p.daemon = True  # 将子进程p设置为守护进程

    p.start()

    time.sleep(1)
    print('皇帝驾崩啦...')

四、进程间数据是隔离的

  • 演示
from multiprocessing import Process
import time
'''
进程间数据是隔离的
'''

number = 10

def func():
    global number
    print('子进程1号')
    number = 100

def func2(number):
    print('子进程2号')
    number += 100

if __name__ == '__main__':
    p_obj = Process(target=func)
    p_obj2 = Process(target=func2, args=(number, ))

    p_obj.start()
    p_obj2.start()

    p_obj.join()
    p_obj2.join()
    time.sleep(1)

    print(f'主进程,{number}') #110  ---> 证明进程间数据不是隔离的
                  #10   ---> 证明进程间数据是隔离的

# 子进程1号
# 子进程2号
# 主进程,10

五、进程互斥锁

  • 演示
from multiprocessing import Process
from multiprocessing import Lock
import random
import time
import json

#抢票例子

#1、查看余票
def search(name):
    #1、读取data.json文件中的数据
    with open('data.json', 'r', encoding='utf-8') as f:
        data_dic = json.load(f)
        print(f'用户{name}查看余票,余票还剩:{data_dic.get("number")}!')

#2、若有余票,购买成功,票数会减少
def buy(name):

    with open('data.json', 'r', encoding='utf-8') as f:
        data_dic = json.load(f)

    #谁先进入这一步代表最先抢到票
    if data_dic.get('number') > 0:
        data_dic['number'] -= 1
        time.sleep(random.randint(1, 3))

        with open('data.json', 'w', encoding='utf-8') as f:
            json.dump(data_dic, f)

        print(f'用户{name}, 抢票成功!')

    else:
        print(f'用户{name}, 抢票失败!')

def run(name, lock):
    #假设1000个用户过来都可以立马查看余票
    search(name)

    lock.acquire()  #加锁
    buy(name)
    lock.release()  #释放锁

if __name__ == '__main__':
    lock = Lock()

    #开启多进程,实现并发
    for line in range(10):
        p_obj = Process(target=run, args=(f'jason{line}', lock))
        p_obj.start()

# 用户jason2查看余票,余票还剩:1!
# 用户jason0查看余票,余票还剩:1!
# 用户jason3查看余票,余票还剩:1!
# 用户jason4查看余票,余票还剩:1!
# 用户jason1查看余票,余票还剩:1!
# 用户jason5查看余票,余票还剩:1!
# 用户jason6查看余票,余票还剩:1!
# 用户jason7查看余票,余票还剩:1!
# 用户jason8查看余票,余票还剩:1!
# 用户jason2, 抢票成功!
# 用户jason0, 抢票失败!
# 用户jason3, 抢票失败!
# 用户jason4, 抢票失败!
# 用户jason1, 抢票失败!
# 用户jason5, 抢票失败!
# 用户jason6, 抢票失败!
# 用户jason7, 抢票失败!
# 用户jason8, 抢票失败!
# 用户jason9查看余票,余票还剩:0!
# 用户jason9, 抢票失败!

六、队列

  • 演示
from multiprocessing import Queue #multiprocessing 提供队列,先进先出
from multiprocessing import JoinableQueue  #JoinableQueue提供队列,先进先出
import queue

#第一种
# q_obj1 = Queue(5)  #此处的5指的是队列中只能存放5份数据
#
# #添加数据到队列中
# q_obj1.put('热巴!')
# print('添加1个啦')
# q_obj1.put('胡歌!')
# print('添加2个啦')
# q_obj1.put('亚峰!')
# print('添加3个啦')
# q_obj1.put('科比!')
# print('添加4个啦')
# q_obj1.put('詹姆斯!')
# print('添加5个啦')

# #注意:put只要队列满了,会进入阻塞状态
# q_obj1.put('sean')
# print('我想添加第六个看会不会报错')

#put_nowait:只要队列满了就会报错
# q_obj1.put_nowait('sean')

# 添加1个啦
# 添加2个啦
# 添加3个啦
# 添加4个啦
# 添加5个啦
# queue.Full

#get:只要队列中有数据,就能获取数据,若没有会进入阻塞状态

# print(q_obj1.get())
# print(q_obj1.get())
# print(q_obj1.get())
# print(q_obj1.get())
# print(q_obj1.get())

#get_nowait:若队列中没有数据获取则会报错
# print(q_obj1.get_nowait())

# 热巴!
# 胡歌!
# 亚峰!
# 科比!
# 詹姆斯!
# _queue.Empty

# #第二种方式
# q_obj1 = JoinableQueue(5)  #此处的5指的是队列中只能存放5份数据
# #添加数据到队列中
# q_obj1.put('热巴!')
# print('添加1个啦')
# q_obj1.put('胡歌!')
# print('添加2个啦')
# q_obj1.put('亚峰!')
# print('添加3个啦')
# q_obj1.put('科比!')
# print('添加4个啦')
# q_obj1.put('詹姆斯!')
# print('添加5个啦')
#
# # #注意:put只要队列满了,会进入阻塞状态
# # q_obj1.put('sean')
# # print('我想添加第六个看会不会报错')
#
# # put_nowait:只要队列满了就会报错
# # q_obj1.put_nowait('sean')
#
#
# # 添加1个啦
# # 添加2个啦
# # 添加3个啦
# # 添加4个啦
# # 添加5个啦
# # queue.Full
#
#
# # get:只要队列中有数据,就能获取数据,若没有会进入阻塞状态
#
#
# print(q_obj1.get())
# print(q_obj1.get())
# print(q_obj1.get())
# print(q_obj1.get())
# print(q_obj1.get())
#
#
# # get_nowait:若队列中没有数据获取则会报错
# # print(q_obj1.get_nowait())
# #
# # 热巴!
# # 胡歌!
# # 亚峰!
# # 科比!
# # 詹姆斯!
# # _queue.Empty

# 第三种方式
q_obj1 = queue.Queue(5)  #此处的5指的是队列中只能存放5份数据

#添加数据到队列中
q_obj1.put('热巴!')
print('添加1个啦')
q_obj1.put('胡歌!')
print('添加2个啦')
q_obj1.put('亚峰!')
print('添加3个啦')
q_obj1.put('科比!')
print('添加4个啦')
q_obj1.put('詹姆斯!')
print('添加5个啦')

#注意:put只要队列满了,会进入阻塞状态
#q_obj1.put('sean')
#print('我想添加第六个看会不会报错')

# put_nowait:只要队列满了就会报错
#q_obj1.put_nowait('sean')

# 添加1个啦
# 添加2个啦
# 添加3个啦
# 添加4个啦
# 添加5个啦
# queue.Full

#get:只要队列中有数据,就能获取数据,若没有会进入阻塞状态

print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())

#get_nowait:若队列中没有数据获取则会报错
#print(q_obj1.get_nowait())

# 热巴!
# 胡歌!
# 亚峰!
# 科比!
# 詹姆斯!
# _queue.Empty

七、IPC(进程间通信)

  • 演示
from multiprocessing import Process
from multiprocessing import JoinableQueue
import time

'''
通过队列可实现进程间通信
'''

def task1(q):
    x = 100
    q.put(x)
    print('添加数据')

    time.sleep(3)
    print(q.get())

def task2(q):
    #想要在task2中获取task1中的x
    res = q.get()
    print(f'获取的数据{res}')
    q.put(9527)

if __name__ == '__main__':
    q = JoinableQueue(10)

    #产生两个不同的子进程
    p1 = Process(target=task1, args=(q, ))
    p2 = Process(target=task2, args=(q, ))

    p1.start()
    p2.start()

# 添加数据
# 获取的数据100
# 9527

八、生产者与消费者

  • 演示
from multiprocessing import JoinableQueue
from multiprocessing import Process
import time

#生产者:生产数据---> 队列
def producer(name, food, q):
    msg = f'{name}生产了{food}食物'

    #生产一个食物添加到牌队列中去
    q.put(food)
    print(msg)

#消费者: 使用数据 <--- 队列
def customer(name, q):
    while True:
        try:
            time.sleep(0.5)

            #若报错,则跳出循环
            food = q.get_nowait()
            msg = f'{name}吃了{food}食物'
            print(msg)

        except Exception:
            break

if __name__ == '__main__':
    q = JoinableQueue()

    #创建10个生产者
    for line in range(10):
        p1 = Process(target=producer, args=('yafeng', f'高级食物{line}', q))
        p1.start()

    #创建两个消费者
    c1 = Process(target=customer, args=('jason', q))
    c2 = Process(target=customer, args=('sean', q))
    c1.start()
    c2.start()

# yafeng生产了高级食物1食物
# yafeng生产了高级食物0食物
# yafeng生产了高级食物2食物
# yafeng生产了高级食物3食物
# yafeng生产了高级食物4食物
# yafeng生产了高级食物5食物
# yafeng生产了高级食物6食物
# yafeng生产了高级食物8食物
# yafeng生产了高级食物7食物
# yafeng生产了高级食物9食物
# jason吃了高级食物1食物
# sean吃了高级食物0食物
# jason吃了高级食物2食物
# sean吃了高级食物3食物
# jason吃了高级食物4食物
# sean吃了高级食物5食物
# jason吃了高级食物6食物
# sean吃了高级食物8食物
# jason吃了高级食物7食物
# sean吃了高级食物9食物

九、线程以及守护线程

  • 开启线程的方式以及理论知识
'''
线程:
    1、什么是线程?
        进程:资源单位
        线程:执行单位

        线程与进程都是虚拟的概念,为了更好表达某种食物

        注意:开启一个进程,一定会自带一个线程,线程才是真正的执行者。

    2、为什么要使用线程?
        节省资源的占用

        - 开启进程:
            -1)会产生一个内存空间,申请一块子资源
            -2) 会自带一个主线程
            -3)开启子进程的速度要比开启子线程的速度慢

        - 开启线程
            -1);一个进程内可以开启多个线程,从进程的内存空间中申请执行单位
            -2):节省资源

        - 开启三个线程
            - 从一个内存资源中,申请三个小的执行单位

        - IO密集型用:多线程
            - IO(时间由用户定):
                - 阻塞:切换 + 保存状态

        - 计算密集型用:多进程
            - 计算(时间由操作系统定):
                - 计算时间很长 ---> 切换 + 保存状态

    注意:进程与进程之间数据是隔离的,线程与线程之间数据是共享的

    3、怎么使用线程?
    from threading import Thread

'''
from threading import Thread
import time

number = 1000

# #启动线程的方式一:
# def task():
#     global number
#     number = 100
#     print('start...')
#     time.sleep(1)
#     print('end...')
#
#
# if __name__ == '__main__':
#     #开启一个子线程
#     t = Thread(target=task)
#     t.start()
#
#     t.join()
#     print('主进程(主线程)...')
#     print(number)
#
# # 主进程(主线程)...
# # 100
# # start...
# # end...

# #开启线程的方式二:
# class MyThread(Thread):
#     def run(self):
#         print('start...')
#         time.sleep(1)
#         print('end...')
#
#
# if __name__ == '__main__':
#     #开启一个子线程
#     t = MyThread()
#     t.start()
#     # t.join()
#     print('主进程(主线程)...')
  • 子线程守护
from threading import current_thread

number = 1000

def task():
    global number
    number = 100
    print(f'start....{current_thread().name}')
    time.sleep(3)
    print(f'end....{current_thread().name}')

if __name__ == '__main__':

    for line in range(10):
        t = Thread(target=task)
        #加上守护线程:主进程结束,代表主线程也结束,子线程可能未被回收
        t.daemon = True
        t.start()

        print(f'主进程(主线程)....{current_thread().name}')
        print(number)

十、线程互斥锁

  • 演示
from threading import Lock
from threading import Thread
import time

#开启10个线程,对一个数据进行修改
number = 100

def task():
    global number

    lock.acquire()
    number2 = number
    time.sleep(1)
    number = number2 - 1
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    list1 = []
    for line in range(10):
        t = Thread(target=task)
        t.start()
        list1.append(t)

    for t in list1:
        t.join()

    print(number)

#>>>> 90

原文地址:https://www.cnblogs.com/yafeng666/p/12003639.html

时间: 2024-10-20 13:47:39

进程,互斥锁,生产者消费者,线程的相关文章

10.22进程互斥锁,队列,堆栈,线程

进程互斥锁 让并发变成串行,牺牲了执行效率,保证了数据的安全. 在程序并发执行时,如果需要修改数据就使用互斥锁. 队列 相当于内存中的空间. 可以存放多个数据,必须排队,遵循先进先出的顺序. from multiprocessing import Queue #调用队列类,实例化队列对象q q = Queue(5) #若传参,队列中就可以存放5个数据 q = Queue() #若不传参,则队列中可以存放无限个数据 q.get() #获取数据 q.put() #添加数据,满了就报错 q.empty

开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型

开启子进程的两种方式 # # # 方式一: # from multiprocessing import Process # import time # # def task(x): # print('%s is running' %x) # time.sleep(3) # print('%s is done' %x) # # if __name__ == '__main__': # # Process(target=task,kwargs={'x':'子进程'}) # p=Process(tar

wait和notify实现的生产者消费者线程交互

public class ProductTest { public static void main(String args[]) { Repertory repertory=new Repertory(); new Thread(new Producer(repertory)).start(); new Thread(new Consumer(repertory)).start(); } } class Repertory{ private int product=0; public sync

使用Win32 API实现生产者消费者线程同步

使用win32 API创建线程,创建信号量用于线程的同步 创建信号量 语法例如以下 HANDLE semophore; semophore = CreateSemaphore(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); CreateSemophore函数的原型例如以下: HANDLE WINAPI CreateSemaphore( _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreA

Java使用FileLock实现Java进程互斥锁

原理:JDK的nio包中FileLock实现类似Linux fcntl的文件锁, 可使文件被进程互斥访问.  借助此功能, 可以实现强大的Java进程互斥锁, 从而在应用层面保证同一时间只有惟一的Jar应用进程在运行! 避免某些因素导致jar重复执行, 多个进程产生竞争,破坏业务数据. (当然, 你可以借助类似ubuntu的upstart脚本或者ps -p <pid>之类的做法来做到相同的功能).实现: package test; import java.io.File; import jav

进程中的生产者消费者模型

# 多进程的生产者消费者模型 # 队列 # 队列是进程安全的,同时只能有一个进程从队列中取到数据 # 生产者消费者模型 # 为什么要这个模型 # 这个模型经常性的解决数据的供需不平衡的问题 # 经常有两拨人,一拨是生产数据的,一拨是消费数据的. # 消费者指的是使用数据处理数据的一端 # 生产数据的一端生产的数据过快 # 当生产数据过快时,消费数据过慢时,可以弄出一个进程队列,将生产的数据放入到队列中,消费数据端可以开多个进程从这个进程队列中消费数据 # 当生产数据过慢时,消费数据过快时,可以弄

Python并发编程03/僵尸孤儿进程,互斥锁,进程之间的通信

目录 Python并发编程03/僵尸孤儿进程,互斥锁,进程之间的通信 1.昨日回顾 2.僵尸进程和孤儿进程 2.1僵尸进程 2.2孤儿进程 2.3僵尸进程如何解决? 3.互斥锁,锁 3.1互斥锁的应用 3.2Lock与join的区别 4.进程之间的通信 进程在内存级别是隔离的 4.1基于文件通信 (抢票系统) 4.2基于队列通信 Python并发编程03/僵尸孤儿进程,互斥锁,进程之间的通信 1.昨日回顾 1.创建进程的两种方式: 函数, 类. 2.pid: os.getpid() os.get

35 守护进程 互斥锁 IPC 共享内存 的方式 生产者消费者模型

守护进程 进程:一个正在运行的程序. 主进程创建守护进程: 1.守护进程会在主进程代码执行结束后就终止, 2.守护进程内无法再开启子进程,否则抛出异常. 注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止. 例子:from multiprocessing import Processimport time def task(): print('老了....') time.sleep(2) print('睡了一会..') if __name__ == '__main__': prin

守护进程,互斥锁,IPC,队列,生产者与消费者模型

小知识点:在子进程中不能使用input输入! 一.守护进程 守护进程表示一个进程b 守护另一个进程a 当被守护的进程结束后,那么守护进程b也跟着结束了 应用场景:之所以开子进程,是为了帮助主进程完成某个任务,然而,如果主进程认为自己的事情一旦做完了就没有必要使用子进程了,就可以将子进程设置为守护进程 例如:在运行qq的过程,开启一个进程,用于下载文件,然而文件还没有下载完毕,qq就退出了,下载任务也应该跟随qq的退出而结束. from multiprocessing import Process

进程 &gt;&gt; 互斥锁、队列与管道、生产者消费者模型

目录 1.互斥锁 2.队列与管道 3.生产者消费者模型(Queue) 4.生产者消费者模型(JoinableQueue) 1.互斥锁 首先导入Lock模块 实例化一把锁 但是每次生成子进程的时候都会重新实例化一把锁,我们的目的是想让所有的子进程使用同一把锁,所以需要把锁传递给子进程在使用 锁名.acquire():开锁->所有子进程开始抢位置 锁名.release():关锁->位置排好了,开始执锁起来执行. join与互斥锁的区别:join是把所有的子进程代码变为串行的,而互斥锁则可以规定那几