Python之多进程和多线程详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lianjiaokeji/article/details/83095187

1.进程的概念

一个CPU的时候运行,轮询调度实现并发执行

在这里插入图片描述
多CPU运行机制:

在这里插入图片描述

计算机程序:存储在磁盘上的可执行二进制(或其他类型)文件。
只有把它们加载到内存中,并被操作系统调用它们才会拥有其自己的生命周期。

进程:表示的一个正在执行的程序。
每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据
操作系统负责其上所有进程的执行,操作系统会为这些进程合理地分配执行时间。

多进程测试

使用多进程测试代码必须两核以上(相当于多个CPU同时运行)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/13 16:26
# @Author  : DoubleChina
# @Site    : 
# @File    : ThreadTest.py
# @Software: PyCharm
import time
import multiprocessing
import os  # 系统模块


def func():
    time.sleep(3)
    i = 0
    for j in range(1000):
        i += 1
    return True


def main():
    start_time = time.time()
    # 创建一个子进程,进程对象
    p = multiprocessing.Process(target=func)
    # 获取当前进程的名字
    # multiprocessing.current_process()
    # 判断这个进程实例,是否还在运行
    # p.is_alive()
    # 不管这个是否在运行,强制杀掉
    # p.terminate()
    # 默认值False,主进程
    p.daemon = True
    # join 等待这个进程结束,主进程才结束
    # p.join()
    # 启动进程
    p.start()
    func()
    end_time = time.time()
    print("子进程:", end_time - start_time)


def get_pid():
    # linux独有的,window上没有
    # linux创建进程,是操作系统把父进程的东西拷贝到子进程,复制进程
    # windows创建进程,类似于模块导入的方法,一定要写main方法,要不会出现执行多次
    pid = os.fork()
    if pid == 0:  # 子进程永远返回的是0
        print('子进程{},父进程{}'.format(os.getpid(), os.getppid()))
    else:  # 父进程返回的是子进程的id
        print('父进程{},子进程{}'.format(os.getpid(), pid))


def main1():
    start_time = time.time()
    func()
    func()
    end_time = time.time()
    print(end_time - start_time)


class BolockProcess(multiprocessing.Process):
    def __init__(self):
        super().__init__()

    def run(self):
        n = 5
        while n > 0:
            print('the time is{}'.format(time.ctime()))
            time.sleep(2)
            n -= 1


def test_BolockProcess():  # 对象继承
    for i in range(5):
        p = BolockProcess()
        p.start()


if __name__ == '__main__':
    # start_time = time.time()
    # main()
    # end_time = time.time()
    # print("主进程:", end_time - start_time)
    # main1()
    # get_pid()
    test_BolockProcess()

单进程运行时间:
22.23472023010254秒
多进程运行速度:
11.984376192092896秒

多进程调用流程:
在这里插入图片描述
计算密集型:在python中,计算密集型用多进程
IO密集型:爬虫典型的IO密集型,用多线程,但是在python中多线程GIL槽糕的设计,比单线程整整慢了45%,但是在Python3以后已经优化了。

2.多线程

线程被称作轻量级进程。
与进程类似,不过它们是在同一个进程下执行的,并且它们会共享相同的上下文。

  • 当其他线程运行时,它可以被抢占(中断)
  • 和临时挂起(也成为睡眠) — 让步

线程的轮训调度机制类似于进程的轮询调度。
只不过这个调度不是由操作系统来负责,而是由Python解释器来负责。

多线程方法详解

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/13 16:26
# @Author  : DoubleChina
# @Site    : 
# @File    : ThreadTest.py
# @Software: PyCharm
import time
import threading


def func():
    i = 0
    for j in range(100000000):
        i += 1
    return True


def main():
    start_time = time.time()
    # 创建一个子进程
    p = threading.Thread(target=func)
    # 线程守护
    p.setDaemon(True)
    # 设置线程名称
    p.setName("线程1")
    # 获取线程名称
    p.getName()
    p.start()

    func()
    end_time = time.time()
    print(end_time - start_time)


def main1():
    start_time = time.time()
    func()
    func()
    end_time = time.time()
    print(end_time - start_time)


class MyThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        time.sleep(2)
        print('I am is{}'.format(self.name))


if __name__ == '__main__':  # 一个文件如果是自己执行  __name__就是main
    # 22.1539466381073秒
    # GIL锁,线程使用在3.6以后有大版本的优化
    # main()
    # 23.165987253189087秒
    # main1()
    thread_list = []
    start_time = time.time()
    for i in range(100):
        t = MyThread('线程{}号'.format(i))
        # 线程守护,主线程结束,子线程也会全部关掉
        t.setDaemon(True)
        t.start()
        # 线程id
        t.ident
        thread_list.append(t)
        # for t in thread_list:
        # 等待子线程结束,主线程阻塞的作用
        # t.join()
    end_time = time.time()
    print(end_time - start_time)

GIL锁

Python在设计的时候,还没有多核处理器的概念。
因此,为了设计方便与线程安全,直接设计了一个锁。
这个锁要求,任何进程中,一次只能有一个线程在执行。
因此,并不能为多个线程分配多个CPU。所以Python中的线程只能实现并发,而不能实现真正的并行。

但是Python3中的GIL锁有一个很棒的设计,在遇到阻塞(不是耗时)的时候,会自动切换线程。

多线程处理Socket并发

服务器:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/13 21:56
# @Author  : DoubleChina
# @Site    : 
# @File    : ThreadSocket.py
# @Software: PyCharm
import socket
import threading

server = socket.socket()
server.bind(('', 9999))
server.listen(5)


def readThread(conn, addr):
    """
    创建一个新的线程,负责和一个客户端通讯
    :param conn:
    :param addr:
    :return:
    """
    while True:
        data = conn.recv(1024)
        if data:
            print('{}:{}'.format(addr, data))
        else:
            print("客户端{}已关闭".format(addr))
            break
    conn.close()


while True:
    print('------主线程,等待客户端连接------')
    conn, addr = server.accept()
    print('创建一个新的线程,和客户端{}通讯'.format(addr))
    # 创建一个子线程,负责消息收发
    client = threading.Thread(target=readThread, args=(conn, addr))
    # 启动线程
    client.start()

客户端:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/13 7:38
# @Author  : DoubleChina
# @Site    :
# @File    : SocketTest.py
# @Software: PyCharm
import socket

# 创建套接字
s = socket.socket()
# 连接套接字,ip和端口必须是服务器上的
s.connect(('127.0.0.1', 9999))
while True:
    data = input("输入发送消息:")
    if 'q' == data:
        s.close()
        break
    s.send(data.encode())
    # print('接受服务器返回的消息:', s.recv(1024))
# s.close()

多进程处理Socket并发

服务器:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/13 21:56
# @Author  : DoubleChina
# @Site    : 
# @File    : ThreadSocket.py
# @Software: PyCharm
import socket
import threading
import multiprocessing

server = socket.socket()
server.bind(('', 9999))
server.listen(5)


def readProcess(conn, addr):
    """
    创建一个新的线程,负责和一个客户端通讯
    :param conn:
    :param addr:
    :return:
    """
    while True:
        data = conn.recv(1024)
        if data:
            print('{}:{}'.format(addr, data))
        else:
            print("客户端{}已关闭".format(addr))
            break
    conn.close()


while True:
    print('------主线程,等待客户端连接------')
    conn, addr = server.accept()
    print('创建一个新的进程,和客户端{}通讯'.format(addr))
    # 创建一个子进程
    p = multiprocessing.Process(target=readProcess, args=(conn, addr))
    p.start()

猜你喜欢

转载自blog.csdn.net/lianjiaokeji/article/details/83095187