zoukankan      html  css  js  c++  java
  • 多任务:进程、线程、协程

    进程 系统进行资源分配和调度的基本单位

    线程 系统独立调度和分派的基本单位 ,是CPU调度的最小单位(程序执行流的最小单元)

    进程切换需要的资源最大,效率最低

    线程切换需要的资源一般,效率一般(当然在不考虑GIL的情况下)

    协程切换任务资源很小,效率高,协程又称微线程

    多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发。

    并发:当多个线程在运行时,如果系统只有一个CPU,它会合理分配给多个线程去执行任务,执行快的多分配,执行慢的少分配。

    并行:当系统有多个CPU时, 线程会分配到不同CPU,互不抢占资源,可以同时进行。

    并发和并行最大的区别就在于,是否同时。

    多进程:在系统同时执行多个不同的任务

    多线程:在单一程序中同时完成多个不同的任务

    区别点

    一个程序至少有一个进程 一个进程至少有一个线程

    进程不共享全局变量,线程可以共享全局变量

    线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享

    多线程(共享全局变量)


    from threading import Thread
    import time

    def work1(nums):
    nums.append(44)
    print("----in work1---",nums)


    def work2(nums):
    #延时一会,保证t1线程中的事情做完
    time.sleep(1)
    print("----in work2---",nums)

    g_nums = [11,22,33]

    t1 = Thread(target=work1, args=(g_nums,))
    t1.start()

    t2 = Thread(target=work2, args=(g_nums,))
    t2.start()

    结论

    在一个线程内对所有线程共享全局变量,很方便多个线程共享数据,但是如果修改全局变量会造成多线程之间的混乱(即线程非安全)

    如果多个线程同时对一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确。

    互斥锁

    目的:当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制

    好处:确保了某段关键代码只能由一个线程从头到尾完整地执行

    坏处:阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了,由于可以存在多个所锁,不同的线程持有不同的锁,并视图获取对方持有的锁时,可能会造成死锁

    # 创建锁
    mutex = threading.Lock()

    # 锁定
    mutex.acquire()

    # 释放
    mutex.release()

    避免死锁

    1、程序设计时尽量避免(银行家算法)

    2、添加超时时间

    进程

    创建进程的方式一:

    复制代码

    import time
    from multiprocessing import Process
    
    
    def test():
        """子进程单独执行的代码"""
        while True:
            print('----test----')
            time.sleep(1)  # 睡眠一秒钟
    
    
    if __name__ == '__main__':
        p = Process(target=test)  # 把函数的名字传到进程中 target会指定一个函数的引用
        p.start()  # 开启进程 当这句话执行时才创建了一个进程
        # 主进程执行代码
        while True:
            print('----main----')
            time.sleep(1)

    复制代码

     总结:

    1.通过额外创建一个进程,可以实现多任务使用进程实现多任务的流程:

    2.创建一个Process对象,且在创建时通过target指定一个函数的引用

    3.当调用start时,会真正的创建一个子进程

    Process创建的实例对象的常用办法:

    1.start():启动子进程实例(创建子进程)

    2.is_live():判断子进程是否还在活着

    3.join([timeout]):是否等待子进程执行结束,或等待多少秒

    terminate():不管任务是否完成,立即终止子进程

    创建进程的方式二:

    复制代码

    import time
    from multiprocessing import Process
    
    
    # 方法二:
    class MyProcess(Process):
        def run(self):
            while True:
                print('----1----')
                time.sleep(1)
    
    
    if __name__ == '__main__':
        p = MyProcess()  # 创建一个MyProcess的对象
        # 当执行到这一句话的时候 会调用p.start()方法,p会先去父类中寻找start(),然后再Process的start方法中调用run方法
        p.start()
        while True:
            print('----main----')
            time.sleep(1)
    复制代码
     
    总结:
     
    1 .此种创建多进程的流程
      1.自定义一个类,继承Process类
      2.实现run方法
      3.通过自定义的类,创建实例对象
      4.调用实例对象的start方法
    2.对比
      自定义继承Process类的方式 比 直接创建Process对象 要稍微复杂一些,但是可以用来实现更多较为复杂逻辑的功能
    3建议 
      1如果想快速的实现一个进程,功能较为简单的话,可以直接创建Process的实例对象
      2如果想实现一个功能较为完整,逻辑较为复杂的进程,可以自定义继承Process类 来实现 
     

    创建进程时传递参数
     
    复制代码
    from multiprocessing import Process
    from time import sleep
    
    
    def test(name, age, **kwargs):
        for i in range(10):
            print('name=%s,age=%d' % (name, age))
            print(kwargs)
            sleep(0.2)
    
    
    if __name__ == '__main__':
        p = Process(target=test, args=('小红', 18), kwargs={'m': 20})
        p.start()
        sleep(1)
        p.terminate()  # 不管任务是否完成,立即终止子进程
        p.join()  # json()会等到子进程结束后主进程才会结束
    复制代码
     
  • 相关阅读:
    C#单纯的字母数字ASCII码转换
    解析类型后加问号和双问号
    【转】composer autoload 自动加载性能优化指南
    【转】Laravel 三种中间件作用讲解
    【转】Laravel belongsTo 详解
    【转】docker-compose详解
    【转】laravel之Artisan命令操作Artisan Console
    【转】Shell中>/dev/null 2>&1 详解
    【转】docker-entrypoint.sh 文件的用处
    【转】解决Debian下sudo命令unable to initialize PAM问题
  • 原文地址:https://www.cnblogs.com/wy919/p/12674889.html
Copyright © 2011-2022 走看看