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)
    
    
  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/bs2019/p/12014448.html
Copyright © 2011-2022 走看看