zoukankan      html  css  js  c++  java
  • 进程 & 线程

    1. 创建 (进程 & 线程)的两种方式:

      进程

    创建进程就是在内存中重新开辟一块内存空间   将允许产生的代码丢进去   一个进程对应在内存就是一块独立的内存空间
    # 第一种方式
    
    from multiprocessing import Process
    import time
    
    
    def test(name):
        print('%s is running'%name)
        time.sleep(3)
        print('%s is over'%name)
    
    """
    windows创建进程会将代码以模块的方式 从上往下执行一遍
    linux会直接将代码完完整整的拷贝一份
    
    windows创建进程一定要在if __name__ == '__main__':代码块内创建  否则报错
    """
    
    if __name__ == '__main__':
        p = Process(target=test,args=('egon',))  # 创建一个进程对象  括号里分别为目标进程,参数(对应为元祖)
        p.start()  # 告诉操作系统帮你创建一个进程
        print('')
    
     # 打印结果:
    #
    # egon is running
    # egon is over
    
    
    
    # 第二种方式:与第一种方式结果一致
    
    from multiprocessing import Process
    import time
    
    
    class MyProcess(Process):
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('%s is running' % self.name)
            time.sleep(3)
            print('%s is over' % self.name)
    
    
    if __name__ == '__main__':
        p = MyProcess('egon')
        p.start()
        print('')

       线程:

    每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中提供代码运行所需要的资源
    # 第一种方式
    
    from threading import Thread
    import time
    
    def task(name):
        print('%s is running'%name)
        time.sleep(3)
        print('%s is over'%name)
    # 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内 t = Thread(target=task,args=('egon',)) t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程 # 小的代码执行完 线程就已经开启了 print('')
    # 执行结果
    # egon is running
    #
    # egon is over
    
    
    # 第二种方式:与第一种方式结果一致
    
    from threading import Thread
    import time
    
    class MyThread(Thread):
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('%s is running'%self.name)
            time.sleep(3)
            print('%s is over'%self.name)
    
    t = MyThread('egon')
    t.start()
    print('')

     2. (进程 & 线程)对象及其他方法

      进程:

    # join方法
    from
    multiprocessing import Process import time def test(name,i): print('%s is running'%name) time.sleep(i) print('%s is over'%name) if __name__ == '__main__': p = Process(target=test,args=('egon',1)) p1 = Process(target=test,args=('kevin',2)) p2 = Process(target=test,args=('jason',3)) start_time = time.time() p.start() # 仅仅是告诉操作系统帮你创建一个进程 至于这个进程什么时候创 操作系统随机决定 p1.start() p2.start() p2.join() p.join() p1.join() # 主进程代码等待子进程运行结束 才继续运行 # p.join() # 主进程代码等待子进程运行结束 print('') print(time.time() - start_time)
    # 执行结果
    egon is running
    kevin is running
    jason is running
    egon is over
    kevin is over
    jason is over
    主
    3.130147695541382
    # 其他方法
    from
    multiprocessing import Process,current_process import os import time def test(name): print('%s is running'%name,current_process().pid) # 获取当前进程的ID print('%s is running'%name,'子进程%s'%os.getpid(),'父进程%s'%os.getppid()) time.sleep(3) print('%s is over'%name) if __name__ == '__main__': p = Process(target=test,args=('egon',)) p.start() p.terminate() # 杀死当前进程 其实是告诉操作系统帮你杀死一个进程 什么时候杀,操作系统决定,并不是直接杀死 time.sleep(0.1) # CPU执行结果很快,休息的这0.1秒基本上就已经把子进程杀死了,所以子进程的操作无效 print(p.is_alive()) # 判断进程是否存活 print('',current_process().pid) print('',os.getpid(),'主主进程:%s'%os.getppid())
    # 执行结果
    False
    主 3441234412 主主进程:28580

      线程:

    from threading import Thread,current_thread,active_count
    import time
    import os
    
    def task(name,i):
        print('%s is running'%name)
        print('子current_thread:',current_thread().name)  # 获取当前线程名
        print('',os.getpid())
        time.sleep(i)
    
        print('%s is over'%name)
    # 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
    t = Thread(target=task,args=('egon',1)) t1 = Thread(target=task,args=('jason',2)) t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程 t1.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程 t1.join() # 主线程等待子线程运行完毕 print('当前正在活跃的线程数',active_count()) # 小的代码执行完 线程就已经开启了 print('') print('主current_thread:',current_thread().name) print('',os.getpid())
    # 执行结果
    egon is running
    子current_thread: Thread-12068
    jason is running
    子current_thread: Thread-22068
    egon is over
    jason is over
    当前正在活跃的线程数 1  # 因为t1的cpu停顿时间大于t,所以在t1休息期间,t就已经执行完了,所以t1执行完毕后就只剩下主线程了
    主
    主current_thread: MainThread2068

    3. (进程 & 线程)数据隔离 问题:

      进程:进程与进程之间数据是隔离的

    from multiprocessing import Process
    
    money = 100
    
    def test():
        global money
        money = 99999999
    
    
    if __name__ == '__main__':
        p = Process(target=test)
        p.start()
        p.join()
        print(money)  # 100 因为每开一个进程,都是新开辟一个新的内存空间,数据互不干扰

    #############################

      进程:资源单位
      线程:执行单位
              将内存比如成工厂
              那么进程就相当于是工厂里面的车间
              而你的线程就相当于是车间里面的流水线
      ps:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中提供代码运行所需要的资源

    ##############################

      线程:同一进程内的线程数据是互联的

    from threading import Thread
    
    money = 666
    
    def task():
        global money
        money = 999
    
    t = Thread(target=task)
    t.start()
    t.join()
    print(money)  # 999

    4. (进程 & 线程)守护  daemon

      进程:主进程死亡,子进程立即死亡

    from multiprocessing import Process
    import time
    
    
    def test(name):
        print('%s总管正常活着'%name)
        time.sleep(3)
        print('%s总管正常死亡'%name)
    
    
    if __name__ == '__main__':
        p = Process(target=test,args=('egon',))
        p.daemon = True  # 将该进程设置为守护进程   这一句话必须放在start语句之前 否则报错
        p.start()
        time.sleep(0.1)  # 不停顿一下速度快直接执行主进程,会导致还没有执行子进程就结束了
        print('皇帝jason寿正终寝')

      线程:

        主线程的结束也就意味着进程的结束**********
        主线程必须等待其他非守护线程的结束才能结束**********
       (因为子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)

    from threading import Thread,current_thread
    import time
    
    
    def task(i):
        print(current_thread().name)
        time.sleep(i)
        print('GG')
    # for i in range(3):
    #     t = Thread(target=task,args=(i,))
    #     t.start()
    t = Thread(target=task,args=(1,))
    t.daemon = True
    t.start()
    print('')
    # 执行结果
    Thread-1

    5. (进程 & 线程)互斥锁

      进程:

    以用户抢票为例:使用互斥锁可以保证同时只有一个用户在对数据进行更改

    虽然降低了执行效率,但是保证了数据的安全性
    #执行前 data 数据
    {"ticket": 3}
    from multiprocessing import Process,Lock
    import time
    import json
    
    # 查票
    def search(i):
        with open('data','r',encoding='utf-8') as f:
            data = f.read()
        t_d = json.loads(data)
        print('用户%s查询余票为:%s'%(i,t_d.get('ticket')))
    
    # 买票
    def buy(i):
        with open('data','r',encoding='utf-8') as f:
            data = f.read()
        t_d = json.loads(data)
        time.sleep(1)
        if t_d.get('ticket') > 0:
            # 票数减一
            t_d['ticket'] -= 1
            # 更新票数
            with open('data','w',encoding='utf-8') as f:
                json.dump(t_d,f)
            print('用户%s抢票成功'%i)
        else:
            print('没票了')
    
    
    def run(i,mutex):
        search(i)
        mutex.acquire()  # 抢锁  只要有人抢到了锁 其他人必须等待该人释放锁
        buy(i)
        mutex.release()  # 释放锁
    
    
    if __name__ == '__main__':
        mutex = Lock()  # 生成了一把锁  要在进程生成之前就加锁
        for i in range(10):
            p = Process(target=run,args=(i,mutex))
            p.start()
    # 执行结果
    用户3查询余票为:3
    用户6查询余票为:3
    用户1查询余票为:3
    用户7查询余票为:3
    用户2查询余票为:3
    用户4查询余票为:3
    用户5查询余票为:3
    用户9查询余票为:3
    用户0查询余票为:3
    用户8查询余票为:3
    用户3抢票成功
    用户6抢票成功
    用户1抢票成功
    没票了
    没票了
    没票了
    没票了
    没票了
    没票了
    # 执行后 data 结果
    {"ticket": 0}

      线程:

    以修改进程内的变量为例
    from threading import Thread,Lock
    import time
    
    n = 10
    
    
    def task(mutex):
        global n
        mutex.acquire()
        tmp = n
        time.sleep(0.1)
        n = tmp - 1
        print(n)
        mutex.release()
    
    
    t_list = []
    mutex = Lock()  # 要在线程创建之前就加锁
    for i in range(10):
        t = Thread(target=task,args=(mutex,))
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(n)
    # 执行结果
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    0

     6. 进程 通信

      进程:队列:先进先出

    """
    子进程放数据 主进程获取数据
    两个子进程相互放 取数据
    """
    
    from multiprocessing import Process,Queue
    
    def producer(q):
        q.put('hello GF~')  # 放值put()
    
    def consumer(q):
        print(q.get())  # 取值get()
    
    if __name__ == '__main__':
        q = Queue()  # 括号内可以传参数 表示的是这个队列的最大存储数  生成一个队列
        p = Process(target=producer,args=(q,))
        c = Process(target=consumer, args=(q,))
        p.start()
        c.start()
    # 此外,还有其他常用的方法:
    
    q.full()  #判断队列是否满了
    q.empty()  # 判断队列中的数据是否取完
    q.get_nowait() # 取值 没有值不等待直接报错
    
    # 当队列满了之后 再放入数据 不会报错 会原地等待 直到队列中有数据被取走(阻塞态)
    # 当队列中的数据被取完之后 再次获取 程序会阻塞 直到有人往队列中放入值
    
    
    """
    full
    get_nowait
    empty
    都不适用于多进程的情况
    """
    
    
    # 适用于多进程的版本
    # 生产者消费者模型
    """ 生产者:生产/制造数据的 消费者:消费/处理数据的 例子:做包子的,买包子的 1.做包子远比买包子的多 2.做包子的远比包子的少 供需不平衡的问题 """ from multiprocessing import Process,JoinableQueue import random import time def producer(name,food,q): for i in range(10): data = '%s生产了%s%s'%(name,food,i) time.sleep(random.random()) q.put(data) print(data) def consumer(name,q): while True: data = q.get() if data == None:break # 如果取完了,就停止 print('%s吃了%s'%(name,data)) time.sleep(random.random()) q.task_done() # 告诉队列你已经从队列中取出了一个数据 并且处理完毕了 # 会有一个计数机制 if __name__ == '__main__': q = JoinableQueue() p = Process(target=producer,args=('大厨egon','馒头',q)) p1 = Process(target=producer,args=('跟班tank','生蚝',q)) c = Process(target=consumer,args=('许兆龙',q)) c1 = Process(target=consumer,args=('吃货jerry',q)) p.start() p1.start() c.daemon = True # 守护进程,待q.join()结束后自动结束 c1.daemon = True c.start() c1.start() p.join() p1.join() q.join() # 等到队列中数据全部取出 自动检测队列里面的值 适用于多线程 每往队列中增加一个值就会自动记录一次

       线程:

        由于同一进程内的线程都是依赖于进程提供资源,所以线程之间的数据是互通的,可实现直接通信,不需要借助第三方

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/pupy/p/11341214.html
Copyright © 2011-2022 走看看