博客
关于我
python 进程 线程 协程(通信方式)
阅读量:585 次
发布时间:2019-03-11

本文共 6430 字,大约阅读时间需要 21 分钟。

进程和线程、协程

在计算机科学中,进程、线程和协程是多任务执行模型的核心概念。这些概念在许多计算机应用中都有广泛的应用,特别是在操作系统和网络开发中。然而,有些人对这三个概念的区别并不明确,因此在这里,我将详细解释这些概念,并探讨它们的应用场景。


进程和线程的区别

进程和线程都是操作系统中执行任务的基本单元,但它们有以下几个关键区别:

  • 进程是:在执行的一个任务,由CPU执行。一个进程可以包含多个线程。

  • 线程是:操作系统的最小调度单位。每个线程在执行时都会ContextHolder的CPU时间片。

  • 进程和线程谁更快:进程无法比线程更快,因为线程是进程调度的基本单位。进程只能通过执行线程来获得并行执行。

  • 启动进程和线程的区别:启动线程比启动进程快。启动线程时需要申请内存空间等资源,而启动进程直接执行指令。

  • 内存空间:线程共享进程的内存空间,进程有独立的内存空间。

  • 创建新线程与新进程:创建新线程比创建新进程简单,因为创建新进程需要复制父进程的内存空间。

  • 操作权限:一个线程可以操作同一进程中的其他线程,而进程只能操作其子进程。


  • 时间片轮询与线程切换

    在操作系统中,线程切换通常通过时间片轮询机制实现。在单线程系统中,每个进程都有私有的虚拟地址空间,进程的所有线程共享同一地址空间。每个线程被CPU分配一个时间片。一旦线程运行完毕,它会被挂起,操作系统会切换到另一个线程继续执行。

    这种轮询机制在多处理器系统中更为高效,因为它允许多个线程在多个CPU上同时运行。不过,即使在单处理器系统中,线程切换看起来也像是多线程同时在运行。


    线程的适用场景

    线程适用于需要大量I/O操作的任务,而不适用于需要高度并行化的CPU密集型任务。例如,网络服务器、文件处理和数据解析等任务通常可以通过线程实现来优化性能。


    线程的实现

    在Python中,线程是通过threading模块实现的。以下是一个典型的线程创建示例:

    import threadingdef run(name):    print(name)    time.sleep(2)threads = [threading.Thread(target=run, args=(i,)) for i in range(10)]for t in threads:    t.start()

    如上所示,可以通过threading.Thread创建多个线程,并设置它们的目标函数和参数。在实际应用中,可以使用类实现线程,以便更好地管理线程的创建和执行。


    多线程的join

    主线程创建子线程后,子线程并不会阻碍主线程的执行。但如果不使用join,主线程在结束后,子线程仍然会继续运行.join()方法可以确保主线程等待子线程完成后再退出。

    def run(name):    for i in range(3):        print(name, i)        time.sleep(2)threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(3)]for t in threads:    t.start()for t in threads:    t.join()print('main finished...')

    守护线程

    默认情况下,主线程退出后,子线程仍然会继续执行。如果希望主线程退出后,子线程也退出,可以将子线程设置为守护线程:

    import threadingdef run(name):    for i in range(3):        print(name, i)        time.sleep(2)threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(3)]for t in threads:    t.setDaemon(True)    t.start()print('main finished...')

    线程同步与互斥锁(递归锁)

    在多线程环境中,同一时间只能有一个线程执行操作,因此需要使用同步机制来确保数据的一致性。Python的threading模块提供了互斥锁(Lock)和递归锁(RLock)来实现线程同步。

    import threadinglock = threading.Lock()num = 0def run(name):    lock.acquire()    global num    num += 1    lock.release()threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(10)]for t in threads:    t.start()for t in threads:    t.join()print('num:', num)

    信号量(并发控制)

    信号量是另一种线程同步机制,它指定了线程的最大数量,以确保一定数量的线程可以同时执行。可以使用multiprocessing.BoundedSemaphore实现信号量。

    import threadinglock = threading.BoundedSemaphore(3)def run(tag):    lock.acquire()    print(tag)    time.sleep(2)    lock.release()threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(10)]for t in threads:    t.start()for t in threads:    t.join()print('main finished...')

    线程的事件控制

    线程可以通过事件来控制彼此的执行。事件可以用于实现线程间的通信和状态传递。

    import threadingevent = threading.Event()def light():    count = 0    while True:        if count < 5:            event.set()            print('\033[42;1m绿灯...%s\033[0m' % count)        elif count > 4:            event.clear()            print('\033[41;1m红灯...%s\033[0m' % count)        time.sleep(1)        count += 1        if count == 10:            count = 0thread_light = threading.Thread(target=light)thread_light.start()def car():    while True:        if event.is_set():            print('绿灯了,我过马路咯')            time.sleep(1)        else:            print('红灯了,等着过马路')        event.wait()thread_car = threading.Thread(target=car)thread_car.start()

    队列(Queue)

    队列是一种高效的任务执行机制,允许多个任务同时等待队列中的数据。通过将任务放入队列,可以实现任务解耦,使程序间提高效率。

    import queueq = queue.Queue(maxsize=2)q.put(1)q.put('domain')try:    q.put('alex', block=False)except Exception as e:    print(e)print(q.qsize())

    生产者与消费者模式

    生产者与消费者模式是一种解耦的任务执行机制,适用于资源有限的环境。生产者负责产生数据,消费者负责处理数据。

    from queue import Queueq = Queue(maxsize=10)def produce():    count = 0    while True:        q.put(count)        print('产生%s' % count)        count += 1        time.sleep(0.5)def consume(name):    while True:        data = q.get()        time.sleep(1)        print('%s消费了%s' % (name, data))thread_produce = threading.Thread(target=produce)thread_consume1 = threading.Thread(target=consume, args=('domain,))thread_consume2 = threading.Thread(target=consume, args=('alex',))thread_produce.start()thread_consume1.start()thread_consume2.start()

    进程

    进程是操作系统的执行单元。一个进程可以包含多个线程,但每个进程都有自己的内存空间。


    创建进程与线程

    在Python中,可以使用multiprocessing模块创建进程,并在进程中创建线程。

    import threadingimport multiprocessingdef info():    print('parent process id:', multiprocessing.current_process().pid)    print('current process id:', multiprocessing.current_process().pid)def run():    threads = [threading.Thread(target=info) for _ in range(2)]    for t in threads:        t.start()        time.sleep(3)if __name__ == '__main__':    info()    processes = [multiprocessing.Process(target=run) for _ in range(1)]    for p in processes:        p.start()        p.join()    print('master process finished...')

    进程间通信

    进程间通信是通过共享内存或通过队列、管道等实现的。以下是一个简单的示例:

    from multiprocessing import Queue, Processq = Queue()def fun(arg):    arg.put('domain')    arg.put('alex')if __name__ == '__main__':    q = Queue()    p = Process(target=fun, args=(q,))    p.start()    print(q.get())

    Pipe通信

    管道是一种简单的共享内存结构,可以用于进程间通信。

    from multiprocessing import Process, Pipedef fun(child):    child.send(['domain', 'alex'])    child.send(['12', '33'])    child.close()if __name__ == '__main__':    parent, child = Pipe()    p = Process(target=fun, args=(child,))    p.start()    print(parent.recv())    print(parent.recv())    parent.send("from parent:hello")    p.join()

    进程池

    进程池是一种固定数量的进程同时执行的方式,适合需要多次并发执行任务的场景。

    from multiprocessing import Pool, osimport timedef run(arg):    print('子进程:', os.getpid())    time.sleep(2)    return os.getpid()if __name__ == '__main__':    print('主进程id:', os.getpid())    pool = Pool(5)    for i in range(20):        if i % 2 == 0:            pool.apply_async(func=run, args=(i,))    pool.close()    pool.join()    print('main finished...')

    协程

    协程(协同可能线程,Greenlet)的概念类似于用户态的轻量级线程,它允许在单线程中实现并行执行。协程在Python中可以通过Greenlet库实现。


    手动切换协程

    from greenlet import greenletdef func1():    print(1)    g2.switch()    print(2)def func2():    print(3)    g1.switch()    print(4)g1 = greenlet(func1)g2 = greenlet(func2)g1.switch()

    自动切换协程(gevent)

    gevent是一个增强版的Greenlet库,提供了更方便的API来实现协程。

    import geventimport timedef func1():    print('在 func1 中,开始了。')    gevent.sleep(2)    print('在 func1 中,结束了。')def func2():    print('在 func2 中,开始了。')    gevent.sleep(1)    print('在 func2 中,结束了。')start_time = time.time()gevent.joinall([    gevent.spawn(func1),    gevent.spawn(func2)])end_time = time.time()print(f'总耗时:{end_time - start_time}')

    总结

    通过对比进程、线程和协程的概念,能够更好地理解它们在操作系统中的作用和应用场景。线程适用于需要大量I/O操作的任务,而进程适用于需要更大的资源隔离需求。协程则提供了一种轻量级的并行执行方式,特别适合I/O密集型任务。

    转载地址:http://itltz.baihongyu.com/

    你可能感兴趣的文章
    IOS开发Swift笔记16-错误处理
    查看>>
    flume使用中的一些常见错误解决办法 (地址已经使用)
    查看>>
    andriod 开发错误记录
    查看>>
    C语言编译错误列表
    查看>>
    看明白这两种情况,才敢说自己懂跨链! | 喵懂区块链24期
    查看>>
    张一鸣:创业7年,我经历的5件事
    查看>>
    git拉取远程指定分支代码
    查看>>
    CentOS5 Linux编译PHP 报 mysql configure failed 错误解决办法
    查看>>
    《web安全入门》(四)前端开发基础Javascript
    查看>>
    pycharm新建文件夹时新建python package和新建directory有什么区别?
    查看>>
    python中列表 元组 字典 集合的区别
    查看>>
    python struct 官方文档
    查看>>
    Android DEX加固方案与原理
    查看>>
    Android Retrofit2.0 上传单张图片和多张图片
    查看>>
    iOS_Runtime3_动态添加方法
    查看>>
    Leetcode第557题---翻转字符串中的单词
    查看>>
    Problem G. The Stones Game【取石子博弈 & 思维】
    查看>>
    Unable to execute dex: Multiple dex files
    查看>>
    Java多线程
    查看>>
    Unity监听日记
    查看>>