zoukankan      html  css  js  c++  java
  • 进程剩余部分和线程

    1创建进程的2种方式

    # 创建进程的2种 方式
    from multiprocessing import Process
    #方式一
    def task():
        pass
    p_obj = Process(target = task)
    #告诉操作系统,让它 去创建一个子进程
    p_obj.start()
    #让主进程等待子进程结束后,在结束,并销毁
    p_obj.join()
    #方式二
    class MyProcess(Process):
        def run(self):
            pass
    p_obj = MyProcess()
    #告诉操作系统,让他创建一个子进程
    p_obj.start()
    #让主进程 等待子进程结束后并销毁
    p_obj.join()
    
    

    2.子进程回收资源的2种方式

    1.join让主进程等待子进程结束后,并回收子进程资源,主进程再结束并回收资源

    2.主进程“正常结束”,子进程也和主进程一并被回收

    from multiprocessing import Process
    import time
    def  task():
        print('start....')
        time.sleep(10)
        print('end...')
    if __name__ == '__main__':
    
        obj = Process(target = task)
        obj.start()
        print('主进程')
        time.sleep(3)
        print('主程序结束')
        
        
    
    

    2.1僵尸进程和孤儿进程

    1.僵尸进程:(有坏处)

    ​ -在子进程结束后,主进程没有正常结束的,子进程的PID不会被回收;

    ​ 缺点:

    ​ -操作系统种的PID号是有限 的,如果子进程的PID无法正常回收,则会占用PID 号;

    ​ -资源浪费

    ​ -若PID号满了,则无法创建新的进程。

    2.孤儿进程(没有坏处):

    ​ -在子进程没有结束时,主进程没有正常的结束,子进程的PID不会被回收;

    ​ -操作系统的优化机制(孤儿院)

    ​ -当主程序意外终止,操作系统的会检测是否有正在运行的子进程,会把放进孤儿院中,让操作系统帮你自动回收,

    PID是操作系统给进程的一个编号,是 有限的,所以在进程结束需要回收。,

    3.守护进程

    定义:当主进程结束后,子进程必须结束,并回收。

    ​ -守护进程必须在守护进程必须在p.start()之前设置, p.daemon = True

    rom multiprocessing import Process
    import time
    def task():
        print('start...')
        time.sleep(1000)
        print('end....')
    if __name__ == '__main__':
        p = Process(target = task)
        #守护进程必须在p.start()之前设置
        p.daemon = True #将子进程设置为守护进程
        #告诉操作系统你开启了子进程
        p.start()
    
        time.sleep(1)
        print('主进程正在进行')
        >>>>>>>>>>>>>>>>>>>>>>>>>>>
     start...
    主进程正在进行
    Process finished with exit code 0
    
    from multiprocessing import Process
    import time
    def demo(name):
        print(f'start...{name}')
        time.sleep(1000)
        print(f'end....{name}')
    if __name__ == '__main__':
        p = Process(target = demo,args = ('童子军json',))
        #守护进程必须在p.start()之前设置
        p.daemon = True #将子进程设置为守护进程
        #告诉操作系统你开启了子进程
        p.start()
    
        time.sleep(1)
        print('主进程正在进行')
        >>>>>>>>>>>>>>>>>>>>>>>>>>
    start...童子军json
    主进程正在进行
    
    Process finished with exit code 0
    

    4.进程间的数据是隔离的

    from multiprocessing import Process
    import time
    number = 10
    def func():
        global number #声明的是全局的变量  下面的number+=10 是可以用的
        number +=10# 如果没有上面的global  这个是会报错
        print(number)
    
    if __name__ == '__main__':
        obj = Process(target = func)
        obj.start()
    
        time.sleep(1)
        print(number) ## 这个是主进程的打印结果
        >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        20
    	10
    

    5.互斥锁

    -互斥锁是一把锁,用来保证数据的读写安全。

    data.json = {"number":1}
    
    from multiprocessing import Process
    from multiprocessing import Lock
    import random
    import time
    import json
    #抢票的例子
    #1查看余票
    def seach(name):
        #读取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个人都可以立马查看余票
        seach(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()
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>这样操作的目地是在def buy哪里加一把锁,让最先进来的人得到 以后的都不允许在进入到这一步,第一个拿到锁以后,然后会释放,第二个进来的人,可以再用。
    用户[jason0]查看余票,余票还剩:[1]
    用户[jason2]查看余票,余票还剩:[1]
    用户[jason1]查看余票,余票还剩:[1]
    用户[jason3]查看余票,余票还剩:[1]
    用户[jason6]查看余票,余票还剩:[1]
    用户[jason4]查看余票,余票还剩:[1]
    用户[jason7]查看余票,余票还剩:[1]
    用户[jason5]查看余票,余票还剩:[1]
    用户[jason8]查看余票,余票还剩:[1]
    用户[jason9]查看余票,余票还剩:[1]
    用户[jason0],抢票成功
    用户[jason2],抢票失败
    用户[jason1],抢票失败
    用户[jason3],抢票失败
    用户[jason6],抢票失败
    用户[jason4],抢票失败
    用户[jason7],抢票失败
    用户[jason5],抢票失败
    用户[jason8],抢票失败
    用户[jason9],抢票失败
    

    6.队列

    -先进先出,先存放的数据 ,就先取出来,相当于一个第三方的管道,可以存放数据

    -应用:可以让进程之间的数据进行交互

    from multiprocessing import Queue #提供对列,先进先出
    from multiprocessing import JoinableQueue  #基于Queue封装的队列,先进先出
    import queue  #python内置的队列 先进先出
    
    #第一种Queue
    #Queue(5)指的是队列中只能存放4个数据
    q_obj1 = Queue(4)
    q_obj1.put('jsaon')
    print('1')
    q_obj1.put('abd')Queue
    print('1')
    q_obj1.put('dbdf')
    print('1')
    q_obj1.put('qwr')
    print('1')
    q_obj1.put('sean')  # 只要队列满了 就会进入堵塞
    print('1')
    >>>>>>>>>>>>>>>>>>>> #下面的这个只有4个1 打印 还有一个因为队列满了 就没有打印 但是也不会报错
    1
    1
    1
    1
    
    q_obj1.put_nowait('sean')###用这个put_nowait 如果满了,是可以报错的
    print('1')
    
    #get:只要队列中有数据,就能获得数据,若没有则会进入阻塞
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())  ##实际只打印了4 个 还有一个没有打印  但是也不会报错
    >>>>>>>>>>>>>>>>>>>>>>>>>>>
    jsaon
    abd
    dbdf
    qwr
    
    #get_nowait:如果对列中没有数据,则会报错
    print(q_obj1.get_nowait())
    
    
    针对于put.nowait和get.nowait 针对第二种和第三种都是适用的
    
    第二种 
    q_obj1 = JoinableQueue(4)
    
    q_obj1.put('jsaon')
    
    print('1')
    q_obj1.put('abd')
    print('1')
    q_obj1.put('dbdf')
    print('1')
    q_obj1.put('qwr')
    print('1')
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    >>>>>>>>>>>>>>>>>>>>>>>
    1
    1
    1
    1
    jsaon
    abd
    dbdf
    qwr
    
    第三种
    q_obj1 = queue.Queue(4)
    
    q_obj1.put('jsaon')
    
    print('1')
    q_obj1.put('abd')
    print('1')
    q_obj1.put('dbdf')
    print('1')
    q_obj1.put('qwr')
    print('1')
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    print(q_obj1.get())
    
    
    

    7.进程间实现通信(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):
        res = q.get()
        print(f'获取的数据是{res}')####这个一步先获取数据
        q.put(9527)
    
    if __name__ == '__main__':
        #产生列队
        q= JoinableQueue(10)
        #产生2个不同子进程
        p1 = Process(target = task1,args = (q,))
        p2 = Process(target = task2,args = (q,))
        p1.start()
        p2.start()
        print('主进程进行中')
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    主进程进行中
    添加数据
    获取的数据是100
    9527
    

    8.生产者和消费者

    -生产者:生产数据

    -消费者:使用数据

    -出现的问题:

    ​ 生产的数据跟不上使用数据的人

    ​ 使用数据的速度跟不上使用数据的速度

    下面的这个例子就是根据队列来实现:解决供需不平衡的问题
    from multiprocessing import JoinableQueue
    from multiprocessing import Process
    import time
    import random
    #生产者 生产数据---->队列
    def producer(name,food,q):
        msg = f'{name}生产了{food}食物'
        #生产一个食物就添加到队列中
        q.put(food)
        print(msg)
    
    #消费者,使用数据
    def customer(name,q):
        while True:
            try:
                time.sleep(random.randint(1,2))
                food = q.get_nowait()#若报错,则跳出循环
                msg = f'{name}吃了{food}食物'
                print(msg)
    
            except Exception:
                break
    
    if __name__ == '__main__':
        q = JoinableQueue()
        #创建2 个生产者
        for line in range(10):
            p1 = Process(target = producer,args =('tank',f'pig饲料{line}',q))
            p1.start()
    
            #创建2个消费者
            c1 = Process(target = customer,args = ('jason',q))
            c2 = Process(target = customer,args = ('sean',q))
            c1.start()
            c2.start()
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    tank生产了pig饲料1食物
    tank生产了pig饲料0食物
    tank生产了pig饲料4食物
    tank生产了pig饲料2食物
    tank生产了pig饲料3食物
    tank生产了pig饲料5食物
    tank生产了pig饲料6食物
    tank生产了pig饲料8食物
    tank生产了pig饲料7食物
    tank生产了pig饲料9食物
    sean吃了pig饲料1食物
    jason吃了pig饲料0食物
    sean吃了pig饲料4食物
    sean吃了pig饲料2食物
    jason吃了pig饲料3食物
    jason吃了pig饲料5食物
    sean吃了pig饲料6食物
    sean吃了pig饲料8食物
    sean吃了pig饲料7食物
    jason吃了pig饲料9食物
    
    

    9.线程

    1.什么是线程?

    ​ 进程:资源单位

    ​ 线程:执行单位

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

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

    2.为什么使用线程?

    ​ 节约资源的占用

    ​ -开启进程:

    ​ 1.会产生一个内存空间,申请一块资源

    ​ 2.会自带一个主线程

    ​ 3.开启子进程的速度要比开启子线程的速度慢

    ​ -开启线程

    ​ 1.一个进程可以开启多个线程,从进程的内存空间中申请执行单位;

    ​ 2.节约资源

    ​ -开启三个进程:

    ​ -占用三分内存资源

    ​ -开启三个线程

    ​ -从一个内存资源中,申请三个小的执行单位

    ​ -IO密集型 多线程

    ​ -计算密集型 多进程

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

    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)
    >>>>>>>>>>>>>>>>>>>>
    start...
    主进程(主线程)
    100
    end...
    
    
    
    
    from threading import Thread
    from multiprocessing import Process
    import os
    def work():
        print('hello',os.getpid())
    
    if __name__ == '__main__':
        #主进程下下面开启的多个线程,每个线程都革命主进程的pid一样
        t1 = Thread(target = work)
        t2 = Thread(target = work)
        t1.start()
        t2.start()
        print('主线程pid',os.getpid())
    
        #开多个进程 每个进程有不同的pid
        p1 = Process(target = work)
        p2 = Process(target = work)
        p1.start()
        p2.start()
        print('主进程pid',os.getpid())
        >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    hello 208580
    hello 208580
    主线程pid 208580
    主进程pid 208580
    hello 208688
    hello 68828
    
    
    

    9.3线程的守护进程

    #启动线程的方式二
    from threading import Thread
    import time
    class MyThread(Thread):
        def run(self):
            print('start...')
            time.sleep(2)
            print('end...')
    
    if __name__ == '__main__':
        t = MyThread()
        t.daemon = True #当主进程结束后,子进程必须结束,并回收。
        t.start()
        print('主进程(主线程)...')
    >>>>>>>>>>>>>>>>>>>>>>>>>>>
    start...
    主进程(主线程)...
    
    Process finished with exit code 0
    
    
    #启动线程的方式二
    from threading import current_thread
    from threading import Thread
    import time
    def task():
    
        print(f'start...{current_thread().name}')   #打印线程的名字
        time.sleep(2)
        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}')
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    start...Thread-1
    主进程(主线程)...MainThread
    start...Thread-2
    主进程(主线程)...MainThread
    start...Thread-3
    主进程(主线程)...MainThread
    start...Thread-4
    主进程(主线程)...MainThread
    start...Thread-5
    主进程(主线程)...MainThread
    start...Thread-6
    主进程(主线程)...MainThread
    start...Thread-7
    主进程(主线程)...MainThread
    start...Thread-8
    主进程(主线程)...MainThread
    start...Thread-9
    主进程(主线程)...MainThread
    start...Thread-10
    主进程(主线程)...MainThread
    
    Process finished with exit code 0
    
    
    
    

    9.4线程的互斥锁

    from threading import Lock
    from threading import Thread
    import time
    lock = Lock()
    number = 100
    #开启10个线程 对一个数据进行修改
    def task():
        global number
        lock.acquire()##这个是加锁
        number -= 1
        time.sleep(1)
    
        lock.release()###这个是去锁
    
    if __name__ == '__main__':
        list = []
        for line in range(4):
            t = Thread(target = task)
            t.start()
            list.append(t)
    
        for t in list:
            t.join()
    
        print(number)
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>
    94
    
    

    9.5线程池

    -线程池是用来限制创建的线程数

    from concurrent.futures import ThreadPoolExecutor
    import time
    #pool只能创建100个线程
    pool = ThreadPoolExecutor(100)
    def task(line):
        a = time.time()
        print(line)
        time.sleep(10)
        b = time.time()
        print(b -a)
    
    if __name__ == '__main__':
        for line in range(1000):
            pool.submit(task,line)
    
    
  • 相关阅读:
    HTML和CSS
    springcloud中配置多数据源
    洛谷 P3800 Power收集(单调队列优化dp)
    洛谷 P2569 [SCOI2010]股票交易(单调队列优化dp)
    洛谷 P3957 [NOIP2017 普及组] 跳房子(二分,单调队列优化dp)
    洛谷 P1419 寻找段落(01分数规划,实数二分,单调队列)
    Prometheus(普罗米修斯)和grafana监控的安装和使用
    AMC如何管理NPL
    linux 正则表达式与字符处理
    react-router-dom switch & match
  • 原文地址:https://www.cnblogs.com/bs2019/p/12014448.html
Copyright © 2011-2022 走看看