python 多进程和多线程

2021-01-19 06:14

阅读:465

标签:and   back   rom   window   自定义   运行   int   最简   lock   

进程就是操作系统中执行的一个程序,操作系统以进程为单位分配存储空间,每个进程都有自己的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据,操作系统管理所有进程的执行,为它们合理的分配资源。进程可以通过fork或spawn的方式来创建新的进程来执行其他的任务,不过新的进程也有自己独立的内存空间,因此必须通过进程间通信机制(IPC,Inter-Process Communication)来实现数据共享,具体的方式包括管道、信号、套接字、共享内存区等。

一个进程可以拥有多个并发的执行线索,简单的说就是拥有多个可以获得CPU调度的执行单元,这就是所谓的线程。

由于线程在同一个进程下,它们可共享相同的上下文,因此相对于进程而言,线程间的信息共享和通信更加容易。当然在单核CPU系统中,真正的并发是不可能的,因为在某个时刻能够获得CPU的只有唯一的一个线程,多个线程共享了CPU的执行时间。

Python中的多进程

Unix和Linux操作系统上提供了fork()系统调用来创建进程,调用fork()函数的是父进程,创建出的是子进程,子进程是父进程的一个拷贝,但是子进程拥有自己的PID。fork()函数非常特殊它会返回两次,父进程中可以通过fork()函数的返回值得到子进程的PID,而子进程中的返回值永远都是0。

Python的os模块提供fork()函数。由于Windows系统没有fork()调用,因此要实现跨平台的多进程编程,可以使用multiprocessing模块的Process类来创建子进程,而且该模块还提供了更高级的封装,例如批量启动进程的进程池(Pool)、用于进程间通信的队列(Queue)和管道(Pipe等。

 

from multiprocessing import Process
from os import getpid
from random import randint
from time import time, sleep

def download_task(filename):
    print(启动下载进程,进程号[%d]. % getpid())
    print(开始下载%s... % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print(%s下载完成! 耗费了%d秒 % (filename, time_to_download))

def main():
    start = time()
    p1 = Process(target=download_task, args=(Python从入门到住院.pdf, ))
    p1.start()
    p2 = Process(target=download_task, args=(Peking Hot.avi, ))
    p2.start()
    p1.join()      # 等待进程执行结束
    p2.join()
    end = time()
    print(总共耗费了%.2f秒. % (end - start))

if __name__ == __main__:
    main()

 

# 用subprocess模块中的类和函数来创建和启动子进程,然后通过管道来和子进程通信

全局变量counter不起作用!!-->-->  用multiprocessing模块中的Queue类,它是可以被多个进程共享的队列,底层是通过管道和信号量(semaphore)机制来实现的

Python中的多线程

from random import randint
from threading import Thread
from time import time, sleep


def download(filename):
    print(开始下载%s... % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print(%s下载完成! 耗费了%d秒 % (filename, time_to_download))

def main():
    start = time()
    t1 = Thread(target=download, args=(Python从入门到住院.pdf,))
    t1.start()
    t2 = Thread(target=download, args=(Peking Hot.avi,))
    t2.start()
    t1.join()
    t2.join()
    end = time()
    print(总共耗费了%.3f秒 % (end - start))


if __name__ == __main__:
    main()

继承Thread类的方式来创建自定义的线程类,然后再创建线程对象并启动线程。

from random import randint
from threading import Thread
from time import time, sleep

class DownloadTask(Thread):
    def __init__(self, filename):
        super().__init__()
        self._filename = filename

    def run(self):
        print(开始下载%s... % self._filename)
        time_to_download = randint(5, 10)
        sleep(time_to_download)
        print(%s下载完成! 耗费了%d秒 % (self._filename, time_to_download))


def main():
    start = time()
    t1 = DownloadTask(Python从入门到住院.pdf)
    t1.start()
    t2 = DownloadTask(Peking Hot.avi)
    t2.start()
    t1.join()
    t2.join()
    end = time()
    print(总共耗费了%.2f秒. % (end - start))


if __name__ == __main__:
    main()

多个线程共享进程的全局变量, 启用锁机制:

from time import sleep
from threading import Thread, Lock


class Account(object):
    def __init__(self):
        self._balance = 0
        self._lock = Lock()

    def deposit(self, money):
        # 先获取锁才能执行后续的代码
        self._lock.acquire()
        try:
            new_balance = self._balance + money
            sleep(0.01)
            self._balance = new_balance
        finally:
            # 在finally中执行释放锁的操作保证正常异常锁都能释放
            self._lock.release()

    @property
    def balance(self):
        return self._balance


class AddMoneyThread(Thread):

    def __init__(self, account, money):
        super().__init__()
        self._account = account
        self._money = money

    def run(self):
        self._account.deposit(self._money)


def main():
    account = Account()
    threads = []
    for _ in range(100):
        t = AddMoneyThread(account, 1)
        threads.append(t)
        t.start()
    for t in threads:
        t.join()
    print(账户余额为: ¥%d元 % account.balance)


if __name__ == __main__:
    main()

 

单线程+异步I/O

利用操作系统提供的异步I/O支持,就可用单进程单线程模型来执行多任务,这种全新的模型称为事件驱动模型。

Nginx就是支持异步I/O的Web服务器,它在单核CPU上采用单进程模型就可以高效地支持多任务。在多核CPU上,可以运行多个进程(数量与CPU核心数相同),充分利用多核CPU。用Node.js开发的服务器端程序也使用了这种工作模式,这也是当下实现多任务编程的一种趋势。

在Python语言中,单线程+异步I/O的编程模型称为协程,可基于事件驱动编写高效的多任务程序。

  1. 极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销。
  2. 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不用加锁,只需要判断状态就好,所以执行效率比多线程高很多。

如果想要充分利用CPU的多核特性,最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

 

python 多进程和多线程

标签:and   back   rom   window   自定义   运行   int   最简   lock   

原文地址:https://www.cnblogs.com/bsszds930/p/12909252.html


评论


亲,登录后才可以留言!