25_python笔记-进程-线程-协程


个人博客
https://blog.csdn.net/cPen_web

#01 Linux操作系统核心 - 内核

内核 操作系统的核心

#内核 操作系统的核心
#linux操作系统 五大子系统
#进程调度 --> linux进程优先级
#文件系统 --> linux ext3 ext4 xfs ,Windows NTFS
#网络接口 --> 端口
#内存管理 --> 虚拟内存 虚拟地址映射 段页机制 缺页中段
#进程通信 --> 管道,信号,消息队列,socket,共享内存

#注:信号用于进程通信
#注:socket一般用于不同主机之间

#02 系统知识

计算机的组成

#计算机的组成:cpu(中央处理器) + 存储(磁盘、内存、外存、缓存) + IO(input/output 输入输出)

资源

#资源
#  1、计算资源   cpu
#  2、存储资源   内存、磁盘等

多任务操作系统

#多任务操作系统
#问:对于单核的cpu能不能同时执行多任务?
#答:可以
#问:能不能真正实现多任务同时执行?
#答:不能,1个cpu 在1个时间段内 只能做1件事情

CPU时间片

# cpu时间片(抽象概念)
# 对于单核cpu同一时刻只能有一个任务运行。
#   1、并发:交替执行(某时间段内的处理能力)
#   2、并行:同时执行

#注:单核cpu而言 并发,多核cpu而言 并行
线程

# 线程 (操作系统进行调度的最小单位)
#它是被包含在进程中,它是进程实际运作的单位

进程

# 进程 (操作系统进行资源分配的最小单位)
#进程:正在运行的程序
#1个进程至少要有1个线程,可以有多个线程,每个线程之间资源是共享进程资源的
#1个标准的线程: 线程ID、当前指令指针(pc)、寄存器集合、堆栈

堆和栈

# 堆和栈
#数据结构上的概念:
#堆 倒立的树
#栈 先进后出

#在操作系统层面:
#系统内存中的堆栈
#堆:内存会大点,由程序自己分配的 动态空间
#栈:由系统分配的使用 一般保存的是一些局部变量

进程和线程

# 进程和线程
#1、1个进程内的线程共享这个进程的空间,进程的内存是独立的
#2、同一个进程的线程之间可以直接交流的;两个进程之间想通信,必须通过代理实现
#3、创建新的线程很简单,但创建一个新的进程 需要对其父进程进行一次克隆
#4、一个线程可以控制和操作同一个进程里的其他线程,进程只能操作子进程
#5、一个主进程改变,可能会影响其他线程,改变父进程不会影响子进程

#多线程的开销会比多进程少

#注:进程 就是运行起来的程序
#注:1个进程最少要有1个线程
#注:线程运行在进程之上
#注:当前指令指针 控制下一条要操作的进程
#注:寄存器集合 CPU从 寄存器集合去捞
#注:系统内存 从低地址到高地址
#注:所有起的进程 都是由父进程创建的

#03 进程状态模型

三态模型
五态模型

运行 ===时间片到==> 就绪
就绪 ==进程调度 ==> 运行
运行  ==等待==> 阻塞
阻塞  ==i/o结束/等待的事情发生==> 就绪
#注:五态模型 多了 新建和终止 (创建进程、终止进程)

#04 抓取网页数据5次 (多线程 threading模块)

deco.py文件

import time

def runtime(func):
    def _runtime(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"函数执行花费了{end - start}s")
        return result
    return _runtime

主程序文件

import requests
import time
from deco import runtime
from threading import Thread    #注:创建多线程
#注:threading里面的Thread是创建线程
def get_content(url):
    text = requests.get(url).content
    time.sleep(0.5)
    #注:get方法请求url
    #注:content获取内容
    print("get content")

@runtime
def main(): #注:包装
    for i in range(5):
        #创建线程
        #target --> 指定要传入方法的名字 ,要做什么
        #args --> 指定方法需要传入的参数 元组类型
        t = Thread(target=get_content,args=("https://www.baidu.com",)) #注:创建线程的实例
        #注:args传元组进去,只有1个参数 需要在后面加,号
        t.start()   #注:启动线程
        # get_content("https://www.baidu.com")
if __name__ == "__main__":   #注:当模块作为主程序运行时,执行
    main()
    print("end......")
#结果为
# 函数执行花费了0.003007650375366211s	#注:父线程只管创建,这是创建的时间
# end......
# get content	#注:使用多线程的情况,时间快
# get content
# get content
# get content
# get content

# main()		#注:不使用多线程的情况 (未导入threading模块时)
#结果为
# get content
# get content
# get content
# get content
# get content
# 函数执行花费了3.173537254333496s	#注:不使用多线程的情况,时间慢
#注:父线程只管创建,子线程还在运行
#注:threading里面的Thread是创建线程

#05 threading - Thread实例方法join

示例

#    t.join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)	#注:可以指定timeout

#注:join方法要用在start后面
#注:阻塞当前环境上下文,直到t的进程执行完成

import requests
import time
from deco import runtime
from threading import Thread

def get_content(url):
    text = requests.get(url).content
    time.sleep(0.5)
    print("get content")

@runtime
def main():
    t_list = [] #注:创建列表
    for i in range(5):
        #创建线程
        #target --> 指定要传入方法的名字 ,要做什么
        #args --> 指定方法需要传入的参数 元组类型
        t = Thread(target=get_content,args=("https://www.baidu.com",))
        t_list.append(t)    #注:把生成的对象加到list里面

        # 启动线程
        t.start()
        #t.join() 如果t.join()加在for循环里面,会等t0执行完了,才会执行t1……一般加在外面
	#注:这样相当于顺序执行,多线程就没有意义了

    for t in t_list:
        #注:阻塞当前环境上下文,直到t的进程执行完成
        t.join()    #注:阻塞当前执行t.join的整个主线程
        #注:等5个t都执行完了,才会往下继续执行(才会输出end......)

if __name__ == "__main__":
    main()
    print("end......")
#结果为
# get content
# get content
# get content
# get content
# get content
# 函数执行花费了0.6949417591094971s
# end......

#注:join方法要用在start后面
#注:阻塞当前环境上下文,直到t的进程执行完成

#06 Thread实例方法

t.name:获取或设置线程的名称
t.is_alive()、t.isAlive():判断线程是否为激活状态。返回线程是否在运行。正在运行指启动后、终止前
t.run():线程被cpu调度后自动执行线程对象的run方法
t.start():线程准备就绪,等待CPU调度,start会自动调用t.run()

#注:真正执行的时候,会调用run方法
示例:name、is_alive

import requests
import time
from deco import runtime
from threading import Thread

def get_content(url):
    text = requests.get(url).content
    time.sleep(0.5)
    print("get content")

@runtime
def main():
    t_list = []
    for i in range(5):
        t = Thread(target=get_content,args=("https://www.baidu.com",),name = "sc-"+str(i))
        t_list.append(t)

        print(t.is_alive())
        t.start()
        print(t.name)
        print(t.is_alive())
        #结果为
        # False
        # sc - 0
        # True
        # False
        # sc - 1
        # True
        # ……
        #结果为
        # Thread - 1
        # ……
        # Thread - 5
        #结果为
        # sc - 0
        # ……
        # sc - 4
    for t in t_list:
        t.join()

if __name__ == "__main__":
    main()
    print("end......")

#07 Thread实例方法 - setDaemon

t.setDaemon(bool): 设置是后台线程(默认前台线程(False))。(在start之前设置)
t.isDaemon:判断是否为后台线程
示例:setDaemon

import requests
import time
from deco import runtime
from threading import Thread

def get_content(url):
    print("start......")
    text = requests.get(url).content
    time.sleep(0.5)
    print("get content...")

@runtime
def main():
    t_list = []
    for i in range(5):
        t = Thread(target=get_content,args=("https://www.baidu.com",),name = "sc-"+str(i))
        #注:默认是前台线程False
        t.setDaemon(True)   #注:设置为后台进程  父线程退出,子线程也退出
        t_list.append(t)

        print(t.is_alive())
        t.start()
        print(t.name)
        print(t.is_alive())

    # for t in t_list:  #注:如果加了join,后台进程不起作用
    #     t.join()

if __name__ == "__main__":
    main()
    print("end......")
#结果为
# False			#注:这些前面的输出随机,每次都不一样
# start......sc-0
# ……
# True
# 函数执行花费了0.0019941329956054688s
# end......

#08 使用自定义线程类

示例:为类添加新的属性

#使用自定义线程类
import threading

#注:重写Thread方法
class MyThread(threading.Thread):   #注:继承threading模块 Thread类
    #注:重写__init__
    def __init__(self, num):
        super().__init__()  #注:继承父进程__init__方法
        self.num = num      #注:添加self.num属性

    #注:重写run方法
    def run(self):  #注:默认线程执行run方法	#注:线程真正执行run里面的
        print(f"running on numbers {self.num}")

if __name__ == "__main__":
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()  #注:不用传参,因为重写了run方法
    t2.start()
#结果为
# running on numbers 1
# running on numbers 2

#09 线程的弊端

·数据前后读取不一致
·资源的争用甚至导致死锁
示例

import threading
import time

num = 0
def sum_num(i):
    global num  #注:申明全局变量
    time.sleep(1)
    num += i
    print(num)

t_list = []
for i in range(6):
    t = threading.Thread(target=sum_num, args=(i,))
    t_list.append(t)
    t.start()

for t in t_list:
    t.join()

print("end...")
#注:出现2个线程共同抢占资源 num
#结果为 (乱的)
# 263   #注:这是一起输出的情况,都是乱的
# 6
#
#
# 11
# 15
# end...

#10 线程 - 互斥锁

示例:互斥锁

#线程 - 互斥锁
#注:访问公共资源的时候 才会涉及到加锁
import threading
import time

num = 0
def sum_num(i):
    lock.acquire()  #注:加锁		# acquire获得
    global num  #注:申明全局变量
    time.sleep(1)
    num += i
    print(num)
    lock.release()  #注:释放锁	# release释放
t_list = []
lock = threading.Lock() #注:创建锁对象

for i in range(6):
    t = threading.Thread(target=sum_num, args=(i,))
    t_list.append(t)
    t.start()

for t in t_list:
    t.join()

print("end...")
#结果为
# 0
# 1
# 3
# 6
# 10
# 15
# end...

#11 LOCK 与 RLOCK

示例:LOCK 与 RLOCK

# LOCK 与 RLOCK  互斥锁
# LOCK不能嵌套使用,嵌套就会导致死锁
# acquire 和 release必须成对存在
# RLOCK是可以嵌套的
import threading
lk1 = threading.RLock() #注:生成 RLOCK锁

print("start......")
lk1.acquire()
print("get acquire 1")
lk1.acquire()
print("get acquire 2")
lk1.release()
print("release acquire 2")
lk1.release()
print("release acquire 1")
#结果为
# start......
# get acquire 1
# get acquire 2
# release acquire 2
# release acquire 1

#注:如果使用LOCK  会产生死锁  卡死了

#12 使用with语句去加锁/解锁

示例:with语句去 加锁/解锁

import threading
import time

num = 0
def sum_num(i):
    with lock:			#注:使用with语句去帮你加锁/解锁
    # lock.acquire()  #加锁		#注:注意代码块的缩进
        global num  #注:申明全局变量
        time.sleep(1)
        num += i
        print(num)
    # lock.release()  #释放锁
t_list = []
lock = threading.Lock() #注:创建锁对象

for i in range(6):
    t = threading.Thread(target=sum_num, args=(i,))
    t_list.append(t)
    t.start()

for t in t_list:
    t.join()

print("end...")

#13 信号量锁

#信号亮锁:最多允许同时N个线程去执行内容
示例

import threading
import time
num = 0

def task():
    with lock:
        global num
        print("sleep 2 s")
        time.sleep(2)
        num += 1
        print(num)

lock = threading.BoundedSemaphore(2)    #注:定义可以有几个线程去执行,给了2把钥匙
for i in range(6):
    t = threading.Thread(target=task)
    t.start()
#结果为
# sleep 2 s     #注:规定同一时刻有2个线程去执行
# sleep 2 s
# 1
# sleep 2 s
# 2
# sleep 2 s
# 3
# sleep 2 s
# 4
# sleep 2 s
# 5
# 6

#14 GIL 全局解释器锁

Python GIL与多线程
	·GIL全称Global Interpreter Lock(全局解释器锁)
	·GIL和Python语言没有任何关系,只是因为历史原因导致在官方推荐的解释器Cpython中遗留的问题(Jpython无此类问题)
	·每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程可以执行代码

#注:只有CPython有,效率慢,多线程基本没有,全局解释器锁,这样多线程没有意义
#注:系统层面的锁	- GIL	全局解释器锁
#注:更细力度资源的锁	- 互斥锁
·GIL最基本的行为只有下面两个:
	1、当前执行的线程持有GIL
	2、当线程遇到io阻塞时,会释放GIL
·由于GIL锁的限制,所以多线程不适合计算型任务,而更适合IO型任务
	·计算密集型任务:用CPU、计算
	=> 多进程
	·IO密集型任务:网络IO(抓取网页数据)、磁盘操作(读写文件)、键盘输入.....
	=> 多线程+多进程

#15 进程

Linux中pid为0的进程,是所有进程的主进程
在python中,每一个运行的程序都有一个主进程,可以利用模块中封装的方法来创建子进程
(os.fork =>linux、multiprocessing)

示例:Linux中pid为0的进程,是所有进程的主进程

[root@cPen_A ~]# ps -ef					#注:PPID 父进程PID号
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 1202 ?      00:00:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2      0  0 1202 ?      00:00:00 [kthreadd]
root          4      2  0 1202 ?      00:00:00 [kworker/0:0H]
[root@cPen_A ~]# ps -ef|grep nginx		
#注:master process ,nginx主进程是pid1的进程创建的
root       3193      1  0 1202 ?      00:00:00 nginx: master process /usr/sbin/nginx

#16 多进程创建

# 创建:用户创建出来的所有进程都是由操作系统负责,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的
# Linux中pid为0的进程,是所有进程的主进程

#在Linux系统 可以使用os.fork()创建 (Windows里没有)
#僵尸进程,孤儿进程
#僵尸进程:创建子进程,如果子进程退出,父进程没有调用wait或者waitpid去获取子进程的状态,
#那么子进程的进程描述符 依然保存在系统中,这种进程称之为僵尸进程

#僵尸进程:一个父进程退出,子进程还在运行,那么这个进程就会成为孤儿进程。孤儿进程会被pid为1的进程所收养

示例:os.fork创建子进程

[root@cPen_A python_test]# vim os_fork_test.py
import os, time #导入os模块

pid = os.fork() #fork出子进程,拷贝一份父进程空间

#父进程运行时pid为子进程的pid,子进程运行时这个pid就为0

print("outerside pid is :",pid)
if pid == 0: #子进程执行时
    print("child process")
    print("child pid is:",os.getpid()) #注:获得当前程序的pid
    print("child-parent pid is:",os.getppid()) #获得父进程pid
else: #父进程执行时
    print("parent process")
    print("parent pid is :",os.getpid())
[root@cPen_A python_test]# python3 os_fork_test.py 
outerside pid is : 5329
parent process
parent pid is : 5328
outerside pid is : 0
child process
child pid is: 5329
child-parent pid is: 5328

示例:僵尸进程

[root@cPen_A python_test]# vim os_fork_test.py
import os, time
pid = os.fork()
print("outerside pid is :",pid)
if pid == 0:
    print("child process")
    time.sleep(1)
    print("child pid is:",os.getpid())
    print("child-parent pid is:",os.getppid())
else:
    print("parent process")
    time.sleep(60)
    print("parent pid is :",os.getpid())
[root@cPen_A python_test]# python3 os_fork_test.py 
……
[root@cPen_A ~]# ps aux |grep python
root       5368  0.0  0.1 125176  5836 pts/0    S+   10:25   0:00 python3 os_fork_test.py
root       5369  0.3  0.0      0     0 pts/0    Z+   10:25   0:00 [python3] <defunct>
#注:S+ 睡眠状态	Z+ 僵尸进程状态
#注:子进程已经结束了,但是系统里的源数据还在。

示例:孤儿进程

[root@cPen_A python_test]# vim os_fork_test.py
import os, time 
pid = os.fork() 
print("outerside pid is :",pid)
if pid == 0:
    print("child process")
    time.sleep(60)
    print("child pid is:",os.getpid())
    print("child-parent pid is:",os.getppid())
else:
    print("parent process")
    #time.sleep(60)
    print("parent pid is :",os.getpid())
[root@cPen_A python_test]# python3 os_fork_test.py 
……
[root@cPen_A ~]# ps -ef |gep os_fork_test
root       5392      1  0 10:33 pts/0    00:00:00 python3 os_fork_test.py
root       5395      1  0 10:33 pts/0    00:00:00 python3 os_fork_test.py
#注:pid1 的进程是所有用户创建的进程的父进程

#17 Multiprocessing

# Multiprocessing
# 由于windows没有fork调用,python提供了multiprocessing支持跨平台版本。
# 创建管理进程模块:
    # Process(用于创建进程模块)
    # Pool(用于创建管理进程池)
    # Queue(用于进程通信,资源共享)
    # Manager(用于资源共享)

示例:使用multiprocessing.Process创建进程

#各个进程都拥有一份数据,相互隔离。 (注:每个进程资源不共享,子进程与父进程空间也是隔离的)
from multiprocessing import Process, current_process
import time

lst = []
def task(i):
    print(current_process().name, i, "start...")
    time.sleep(2)
    lst.append(i)
    print(id(lst))
    print(lst)
    print(current_process().name, i, "ending...")

if __name__ == "__main__":
    for i in range(4):
        p = Process(target = task, args=(i,))
        p.start()
#结果为
# Process-1 0 start...
# Process-4 3 start...
# Process-2 1 start...
# Process-3 2 start...
# 2382436580352
# [0]
# Process-1 0 ending...
# 2222389869568
# [3]
# Process-4 3 ending...
# 2609488870400
# [1]
# Process-2 1 ending...
# 2225376017408
# [2]
# Process-3 2 ending...

#各个进程都拥有一份数据,相互隔离。 (注:每个进程资源不共享,子进程与父进程空间也是隔离的)

示例:使用multiprocessing.Process自定线程类创建进程类

#类创建 继承Process类 重写run方法
from multiprocessing import Process, current_process
class A(Process):
    def __init__(self,i):   #注:重写init
        super().__init__()  #注:访问父类init函数
        self.i = i          #注:增加属性i
    def run(self) -> None:  #注:-> None 函数期望返回None
        print(current_process().name, self.i, "start...")
        time.sleep(2)
        lst.append(self.i)
        print(id(lst))
        print(lst)
        print(current_process().name, self.i, "end...")

if __name__ == "__main__":
    for i in range(4):
        p = A(i)
        p.start()

#18 数据共享-Manager

示例

#数据共享-Manager
from multiprocessing import Process, Manager

def func(i,temp):
    temp[0] += 100
    print(i, "------>", temp[0])

if __name__ == "__main__":
    mange = Manager()
    p_list = []
    temp = mange.list([11,22,33])   #注:共享
    # temp = [11,22,33] #注:不共享
    for i in range(3):
        p = Process(target= func, args=(i,temp))
        p.start()
        p_list.append(p)

    #一定要加join,等待子进程全部结束,父进程再退出
    [p.join() for p in p_list]  #注:列表推导式

    print("ending......")
#结果为
# 2 ------> 111
# 0 ------> 211
# 1 ------> 311
# ending......
#注:不共享的情况下
# 1 ------> 111
# 0 ------> 111
# 2 ------> 111
# ending......

示例:加锁

#数据共享-Manager
from multiprocessing import Process, Manager
from multiprocessing import Lock

lock = Lock()   #注:实例化锁
def func(i,temp):
    with lock:  #注:加锁
        temp[0] += 100
        print(i, "------>", temp[0])

if __name__ == "__main__":
    mange = Manager()
    p_list = []
    temp = mange.list([11,22,33])   #注:共享
    lock = Lock()
    # temp = [11,22,33] #注:不共享
    for i in range(10):
        p = Process(target= func, args=(i,temp))
        p.start()
        p_list.append(p)

    #一定要加join,等待子进程全部结束,父进程再退出
    [p.join() for p in p_list]  #注:列表推导式

    print("ending......")
#结果为
# 3 ------> 111
# 5 ------> 211
# 6 ------> 311
# 7 ------> 411
# 0 ------> 511
# 2 ------> 611
# 8 ------> 711
# 9 ------> 811
# 1 ------> 911
# 4 ------> 1011
# ending......

#19 数据共享-Queue消息队列

实例方法:
# put(obj [, block=True[, timeout]]):调用队列对象的put()方法将obj插入到队列中
# get([block=True[, timeout]]):get方法可以将队列中读取并删除一个元素
# full():判断队列是否为满
# empty():判断队列是否为空
# qsize():获取队列中消息数量

示例

#数据共享-Queue
#队列:先进先出
from multiprocessing import Process, Queue
import time

def func(i,q):
    if not q.empty():   #注:队列非空
        print(i,"------>get value",q.get()) #注:get 从队列里面取,读一个少一个
    time.sleep(2)

if __name__ == "__main__":
    p_lst = []
    q = Queue()
    for i in range(6):
        #往队列里存放数据 put,放一个多一个
        q.put(10-i) #注:10 9 8 7 6 5
        p = Process(target=func, args=(i,q)) #注:创建进程
        p.start()
#结果为    (前面的顺序由系统调度决定)
# 2 ------>get value 10
# 1 ------>get value 9
# 0 ------>get value 8
# 3 ------>get value 7
# 4 ------>get value 6
# 5 ------>get value 5

#20 进程与多进程-multiprocessing.Pool

# Pool 类
# 注意:
# 	① 使用Pool创建进程池对象,同时进程池中进程已经启动
# 	② 向进程池对象中添加事件,事件排队执行
# 	③ 如果主进程退出,则进程池中所有进程都退出

#注:Queue不能再Pool进程池中使用,使用Multiprocessing.Manager类可以适用Pool类

示例

#建议设置的进程数和cpu核数一致
from multiprocessing import Pool, current_process
import time

lst = []
def task(i):
    print(current_process().name, i, "start...")
    time.sleep(10)
    lst.append(i)
    print(lst)
    print(current_process().name, i, "ending...")

if __name__ == "__main__":
#建议设置的进程数和cpu核数一致
    p = Pool(processes=4) #指定进程池内有4个进程 创建实例
    # p = Pool(processes=4,maxtasksperchild=2) #指定进程池内有4个进程,且只能处理2个任务
    pool_lst = []
    for i in range(20):
        p.apply_async(func=task, args=(i,)) #注:非阻塞
	# p.apply(func=task, args=(i,))   #注:阻塞的,多进程没有意义
    #池子不再接受任务
    p.close()
    #等待子进程执行完毕
    p.join()
    print("end......")
#结果为
# SpawnPoolWorker-2 0 start...
# SpawnPoolWorker-3 1 start...
# SpawnPoolWorker-1 2 start...
# SpawnPoolWorker-4 3 start...
# [0]
# SpawnPoolWorker-2 0 ending... #注:2号进程处理结束0号任务
# SpawnPoolWorker-2 4 start...  #注:2号进程处理4号任务
# [1]
# ……
# [0, 4]			#注:进程与进程之间 空间相互独立
# SpawnPoolWorker-2 4 ending... #注:2号进程处理结束4号任务
# ……
# SpawnPoolWorker-4 19 ending...
# end......

#注:进程不销毁,内存不释放。内存占用过多 可能会出现oom(out of momery 要申请的内存不够了)

示例:maxtasksperchild

if __name__ == "__main__":
    p = Pool(processes=4,maxtasksperchild=2) #指定进程池内有4个进程 创建实例
    #注:进程只能处理2个任务,处理结束后销毁,创建新的进程
…………
#结果为
# SpawnPoolWorker-3 0 start...
# SpawnPoolWorker-2 1 start...
# SpawnPoolWorker-1 2 start...
# SpawnPoolWorker-4 3 start...
# SpawnPoolWorker-8 14 ending...
# ……
# [11, 15]
# SpawnPoolWorker-7 15 ending...
# [19]
# ……
# SpawnPoolWorker-12 19 ending...
# end......

示例:watch

#watch 监测命令的运行结果
[root@cPen_A ~]# watch "ps -ef |grep python"
Every 2.0s: ps -ef |grep python                                                                                             root       1039      1  0 1202 ?      00:00:10 /usr/bin/python2 -Es /usr/sbin/tuned -l -P
root       6640   5629  2 16:03 pts/3    00:00:00 python3 pool_test.py
……
root       6644   6640  0 16:03 pts/3    00:00:00 python3 pool_test.py
[root@cPen_A python_test]# ulimit -a			#注:当前用户的所有限制
open files                      (-n) 1024		#注:1个进程最大可以打开的文件数
[root@cPen_A python_test]# ulimit -n 65535	#注:临时修改
[root@cPen_A python_test]# ulimit -a
open files                      (-n) 65535
#注:配置文件 /etc/security		limits.conf  limits.d/    
[root@cPen_A security]# pwd
/etc/security
[root@cPen_A security]# ls limits.
limits.conf  limits.d/    

#21 pool和process的比较

Python中多进程与多线程
·多进程与多线程的选择
1、io密集型计算用多线程	#注:process
2、cpu密集型计算用多进程	#注:pool

示例:CPU密集型

[root@cPen_A python_test]# vim pool_test.py 
from multiprocessing import Pool, current_process
import time

lst = []
def task(i):
    li = []
    for i in range(10**3):
        li.append(i)

if __name__ == "__main__":
    p = Pool(processes=4)
    pool_lst = []
    for i in range(2000):
        p.apply_async(func=task, args=(i,))
    #池子不再接受任务
    p.close()
    #等待子进程执行完毕
    p.join()
    print("end......")
[root@cPen_A python_test]# vim process_test.py
from multiprocessing import Pool, current_process, Process
import time

lst = []
def task(i):
    li = []
    for i in range(10**3):
        li.append(i)

if __name__ == "__main__":
    #p = Pool(processes=4)
    p_lst = []
    for i in range(2000):
        p = Process(target = task, args=(i,))
        p.start()
        p_lst.append(p)
    [p.join() for p in p_lst]
    print("end......")
[root@cPen_A python_test]# time python3 pool_test.py 
end......
real	0m0.408s
user	0m0.476s
sys	0m0.055s
[root@cPen_A python_test]# time python3 process_test.py 
end......
real	0m4.497s
user	0m2.522s
sys	0m6.235s

示例:IO密集型

[root@cPen_A python_test]# vim process_test_io.py 
from multiprocessing import Pool, current_process, Process
import time

lst = []
def task(i):
    li = []
    for i in range(10**3):
        li.append(i)

if __name__ == "__main__":
    p = Pool(processes=4)
    p_lst = []
    for i in range(20):
        p = Process(target = task, args=(i,))
        p.start()
        p_lst.append(p)
    [p.join() for p in p_lst]
    print("end......")
[root@cPen_A python_test]# vim pool_test_io.py 
from multiprocessing import Pool, current_process
import time
import os
lst = []
def task(i):
    print(os.getpid)
    time.sleep(1)

if __name__ == "__main__":
    p = Pool(processes=4)
    pool_lst = []
    for i in range(20):
        p.apply_async(func=task, args=(i,))
    #池子不再接受任务
    p.close()
    #等待子进程执行完毕
    p.join()
    print("end......")
[root@cPen_A python_test]# time python3 process_test_io.py 
end......
real	0m1.953s
user	0m0.164s
sys	0m3.466s
[root@cPen_A python_test]# time python3 pool_test_io.py 
<built-in function getpid>
……
<built-in function getpid>
end......
real	0m5.126s
user	0m0.093s
sys	0m0.028s

#22 生产者消费者模式

示例:多线程实现生产者消费者模式

#多线程实现生产者消费者模式
import time
import queue, threading

q = queue.Queue()   #注:queue有单独的模块

def producer(): #注:生产者
    while True:
        print("xx生产了一辆车")
        q.put("xx生产了一辆车")   #注:往队列里插入数据
        time.sleep(1)

def consumer(): #注:消费者
    while True:
        print("我买了一辆车", q.get())    #注:取数据
        time.sleep(1)

t1 = threading.Thread(target=producer)  #注:创建进程
t1.start()
t2 = threading.Thread(target=consumer)
t2.start()
#结果为
# xx生产了一辆车
# 我买了一辆车 xx生产了一辆车
# xx生产了一辆车
# 我买了一辆车 xx生产了一辆车
# ……
#开放式问题  一个东西的解决方案?
#注:消息中间件:消息中间存放的位置。把日志存放在一个集中的地方做存储 消息中间件
#注:生产者:后端集群
#注:消息中间件 - 中间存储 - 缓存	kafka	rabbitmq	nsq
#注:消费者:分析 - 服务器
#注:消息中间件	kafka	rabbitmq	nsq

#23 协程概念

在进程之上划分很多线程,在线程之上 划分很多协程
#注:堆区是由用户自己申请的
#注:栈区是系统分配的,保存临时变量
#注:协程是运作在1个线程之上的,2个协程不能相互控制

示例

#注:协程   切换由用户控制
#注:进程和线程 由系统控制
#生成器
#yield实现
def jumping_range(n):
    index = 0
    while index < n:
        print("index ", index)
        yield index     #注:yield 保存上下文关系
        index += 1
        print("end......index")

if __name__ == "__main__":
    itr = jumping_range(5)
    print(next(itr))
    print(next(itr))
#结果为
# index  0
# 0
# end......index
# index  1
# 1
#注:yield和return不一样。return没有上下文,下一次执行 从头开始执行

#注:协程主要运作在非阻塞异步并发处理上面,Python的协程 3.4之后 才发展起来

#24 同步 异步 阻塞 非阻塞

注:同步 阻塞:比如发起io请求,主动获取服务器发送数据。这中间什么都不做,就被阻塞
阻塞:等数据的状态,什么都不做
同步 非阻塞:主动获取数据的过程中,做其他事情
异步:自己不需要主动去获取消息,数据准备好了通知自己就行了

同步和异步:关注的是消息通信机制	(主动获取消息 还是 被动获取消息)
阻塞和非阻塞:关注的是程序在等待调用结果时的状态

异步编程

协程的缺点:
·无法利用多核资源

#25 asyncio协程

示例:asyncio 异步io 协程对象

#asyncio 异步io 协程对象
import asyncio
import time

async def func1():  #注:变为异步函数
    print(1)
    await asyncio.sleep(2)  #注:等待2s
    print(2)

async def func2():
    print(3)
    await asyncio.sleep(2)
    print(4)

#任务列表
tasks = [
    asyncio.ensure_future(func1()), #注:执行func1
    asyncio.ensure_future(func2())
]

#生成一个事件循环
loop = asyncio.get_event_loop() #注:生成一个事件循环对象
#asyncio.wait 等待,给出已完成和已挂起的任务
loop.run_until_complete(asyncio.wait(tasks))    #注:运行直到完成,wait等待
#结果为
# 1
# 3
# 2
# 4
#注:先输出1 3 ,再输出2 4
#注:从这里切换到那里,切换由自己控制
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mycpen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值