【python】第四模块:网络编程进阶&数据库开发 第1章·网络编程进阶

  • 01-进程与程序的概念
  • 02-操做系统介绍
  • 03-操做系统发展历史-第一代计算机
  • 04-操做系统发展历史-批处理系统
  • 05-操做系统发展历史-多道技术
  • 06-操做系统发展历史-分时操做系统
  • 07-总结操做系统功能与多道技术
  • 08-进程理论
  • 09-开启子进程的两种方式
  • 10-查看进程的pid与ppid
  • 11-僵尸进程与孤儿进程
  • 12-Process对象的其余属性或方法
  • 13-练习题讲解
  • 14-守护进程
  • 15-互斥锁
  • 16-模拟抢票
  • 17-互斥锁与join的区别
  • 18-队列的使用
  • 19-生产者消费者模型
  • 20-JoinableQueue的使用
  • 21-什么是线程
  • 22-开启线程的两种方式
  • 23-进程与线程的区别
  • 24-Thread对象的其余属性或方法
  • 25-守护线程
  • 26-互斥锁
  • 27-GIL的基本概念
  • 28-GIL与互斥锁的区别
  • 29-GIL与多线程
  • 30-死锁与递归锁
  • 31-信号量
  • 32-Event事件
  • 33-定时器
  • 34-线程queue
  • 35-多线程实现并发的套接字通讯
  • 36-进程池线程池
  • 37-异步调用与回调机制
  • 38-进程池线程池小练习
  • 39-协程介绍
  • 40-greenlet模块
  • 41-greenlet模块
  • 42-gevent模块
  • 43-gevent异步提交任务
  • 44-基于gevent模块实现并发的套接字通讯
  • 45-IO模型介绍
  • 46-阻塞IO模型
  • 47-非阻塞IO模型
  • 48-多路复用IO模型
  • 49-异步IO模型

01-进程与程序的概念

一、进程,即正在执行的一个过程,是一个抽象的概念,起源于操做系统,是操做系统的核心概念,也是操做系统提供的最古老也是最为重要的抽象概念之一;

二、操做系统的其余全部内容都是围绕进程的概念展开的;

02-操做系统介绍

一、操做系统的做用;

  • 隐藏丑陋的硬件接口,提供良好的抽象接口;
  • 管理、调度进程,而且将多个进程对硬件的竞争变得有序;

03-操做系统发展历史-第一代计算机

一、操做系统发展史;

1)第一代计算机(1940~1955)python

  • 特色:没有操做系统的概念;也没有编程语言的概念;全部的程序设计都是直接操做硬件;
  • 优势:程序员在申请的时间段内独享整个资源,能够即时地调试本身的程序(有Bug能够及时处理)
  • 缺点:浪费计算资源,一个时间段里只能有一我的用;注意:同一时刻只有一个程序在内存中,被CPU调用执行,比方说10个程序的执行,都是串行的;

04-操做系统发展历史-批处理系统

一、第二代计算机(1955~1965):晶体管和批处理系统程序员

05-操做系统发展历史-多道技术

06-操做系统发展历史-分时操做系统

07-总结操做系统功能与多道技术

08-进程理论

09-开启子进程的两种方式

一、multiprocessing模块介绍;

二、Process类的介绍;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 4:14 PM
""
"""
开启子进程的两种方式
"""
#开启进程的方式1:
from multiprocessing import Process
import time

def task(name):
    """
    任务函数
    :param name:
    :return:
    """
    print('%s is running'%name)
    time.sleep(3)
    print('%s is done'%name)

if __name__ == '__main__':
#Process(target= task, kwargs={'name':'子进程1'})
    p = Process(target = task, args = ('子进程1',))
    p.start()#仅仅只是给操做系统发送了一个信号;
    print('主')
"""
主
子进程1 is running
子进程1 is done
"""

"""
开启进程的方式2:
"""
from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):#默认必须叫作run
        print('%s in running'%self.name)
        time.sleep(3)
        print('%s is done'%self.name)

if __name__ == '__main__':
    p = MyProcess('子进程1')
    p.start()
    print('主')
"""
主
子进程1 in running
子进程1 is done
"""
复制代码

10-查看进程的pid与ppid

一、pid即process id(进程号)

二、ppid即parent process id(父进程号)

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 4:52 PM
""
"""
10-查看进程的pid与ppid
操做系统管理进行,使用pid号,相似人类的身份证号;
"""
from multiprocessing import  Process
import time
import os

def task():
    print('%s is running,partent id is <%s>'%(os.getpid(),os.getppid()))
    time.sleep(3)
    print('%s is done,partent id is <%s>'%(os.getpid(),os.getppid()))

if __name__ == '__main__':
    #p = Process(target= task, args=('子进程1'))#TypeError: task() takes 0 positional arguments but 4 were given
    p = Process(target= task,)
    p.start()

    print('主%s,partent id is <%s>'%(os.getpid(),os.getppid()))
"""
主 12040
16924 is running
16924 is done
----------------------
主888,partent id is <14600>
19400 is running,partent id is <888>
19400 is done,partent id is <888>
-----------------------------------
C:\\Users\\TQTL911>tasklist |findstr pycharm
pycharm64.exe                14600 Console                    6    823,488 K

C:\\Users\\TQTL911>
"""
复制代码

11-僵尸进程与孤儿进程

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 5:07 PM
""
"""
11-僵尸进程与孤儿进程;
此内容了解为主;
一、僵尸进程,即子进程被杀死后的状态,方便于父进程查看一些状态信息,但他是有害的;
二、孤儿进程,即父进程终止后,保存的子进程,但会交由祖宗进程init(全部进程的起点,即孤儿院)去进行管理,它是无害的;
"""
复制代码

12-Process对象的其余属性或方法

一、join方法;

二、Process对象的其余属性或方法;terminate与is_alive以及name与pid

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 5:17 PM
""
"""
12-Process对象的其余属性或方法

"""
#一、join方法讲解
from multiprocessing import Process
import time
import os
import random

def task():
    print('%s is running,The parent id is <%s>'%(os.getpid(),os.getppid()))
    time.sleep(random.randrange(1,5))
    print('%s is down,The parent id is <%s>'%(os.getpid(),os.getppid()))

if __name__ == '__main__':
    p = Process(target=task,)
    p.start()

    p.join()#保证等待子进程执行结束,父进程才执行
    print('主',os.getpid(),os.getppid())
    print(p.pid)
#二、引入join方法
from multiprocessing import Process
import time
import os
import random

def task(name):
    print('%s is running'%name)
    time.sleep(random.randrange(1,3))

if __name__ == '__main__':
    p1 = Process(target=task,args=('子进程1',))
    p2 = Process(target=task,args=('子进程2',))
    p3 = Process(target=task,args=('子进程3',))
    p4 = Process(target=task,args=('子进程4',))
    p1.start()#只是发个信号给操做系统,至于CPU执行的顺序,由操做系统来分配;
    p2.start()
    p3.start()
    p4.start()

    p1.join()#保证等待子进程执行结束,父进程才执行
    p2.join()#保证等待子进程执行结束,父进程才执行
    p3.join()#保证等待子进程执行结束,父进程才执行
    p4.join()#保证等待子进程执行结束,父进程才执行
    print('主',os.getpid(),os.getppid())
"""
一、不曾使用join方法的时候,执行的顺序以下所示:
主 14188 14600
子进程1 is running
子进程3 is running
子进程2 is running
子进程4 is running
二、使用了join方法以后,执行的顺序以下所示:
子进程1 is running
子进程2 is running
子进程3 is running
子进程4 is running
主 2564 14600
"""

#三、并行执行程序;
from multiprocessing import Process
import os
import random
import time

def task(name,n):
    print('%s is runing'%name,10)
    time.sleep(n)

if __name__ == '__main__':
    start = time.time()
    p1 = Process(target= task, args=('子进程1',5))
    p2 = Process(target= task, args=('子进程2',3))
    p3 = Process(target= task, args=('子进程3',2))

    p1.start()
    p2.start()
    p3.start()

    p1.join()
    p2.join()
    p3.join()
    print('主',(time.time() - start))
"""
子进程1 is runing 10
子进程3 is runing 10
子进程2 is runing 10
主 5.093375205993652    
"""


#四、变成串行方式执行程序;
from multiprocessing import Process
import os
import time

def task(name,n):
    print('%s is running'%name,n)
    time.sleep(n)

if __name__ == '__main__':
    start = time.time()
    # p1 = Process(target= task,args=('子进程1',5),)
    # p2 = Process(target= task,args=('子进程2',1),)
    # p3 = Process(target= task,args=('子进程3',2),)
    #
    # p1.start()
    # p1.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()
#对以上内容的简写
    p1 = Process(target=task, args=('子进程1', 5), )
    p2 = Process(target=task, args=('子进程2', 1), )
    p3 = Process(target=task, args=('子进程3', 2), )
    p_l = [p1,p2,p3]
    for p in p_l:
        p.start()
    for p in p_l:
        #p.join()#TabError: inconsistent use of tabs and spaces in indentation
        p.join()
#print('主',time.time() - start)#NameError: name 'start' is not defined
    print('主',time.time() - start)
"""
子进程1 is running 5
子进程2 is running 1
子进程3 is running 2
主 8.224236726760864
"""

#小结
from multiprocessing import Process
import os
import time
import random

def task():
    print('%s is runing,The parent id is <%s>'%(os.getpid(),os.getppid()))
    time.sleep(random.randrange(1,3))
    print('%s is done,The parent id is <%s>'%(os.getpid(),os.getppid()))

if __name__ == '__main__':#尽量手写,不使用main自动生成,会出现tab != 4个空格的坑呀!
    # p = Process(target= task,)
    # p.start()
    # p.join()
    # print('主',os.getpid(),os.getppid())
    # print(p.pid)
    # print(p.is_alive())#布尔值False or True
    p = Process(target=task,)
    p.start()
    p.terminate()
    time.sleep(3)#加上时间后,is_alive将会变成False
    print(p.is_alive())#True
    print('主',os.getpid(),os.getppid())
复制代码

13-练习题讲解

一、改写下列程序,分别别实现下述打印效果;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 6:53 PM
from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(random.randrange(1,3))
    print('--------->%s'%n)

if __name__ == '__main__':
    p1 = Process(target=task,args=(1,))
    p2 = Process(target=task,args=(2,))
    p3 = Process(target=task,args=(3,))
# Req1:最早保证输出--------->4
    p1.start()
    p2.start()
    p3.start()
    print('最早保证输出--------->4')

#Req2:保证最后输出--------->4
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    print('保证最后输出--------->4')

#Req3:保证按顺序输出--------->4
#以下写,变成串行,失去并发的意义,没有意义,为了练习join方法的使用;
    p1.start()
    p1.join()
    p2.start()
    p1.join()
    p3.start()
    p1.join()
    print('保证按顺序输出--------->4')
复制代码

二、基于多进程实现并发套接字通讯;

1)server端;数据库

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 6:37 PM
from socket import *
from multiprocessing import Process

def talk(conn):
    while True:
        try:
            data = conn.recv(1024)
            if not data:break
            conn.send(data.upper())
        except ConnectionResetError:
            break
        conn.close()

def server(ip,port):
    server = socket(AF_INET,SOCK_STREAM)
    server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    server.bind((ip,port))#注意此处为元组形式的ip_port:(ip,port)
    server.listen(5)

    while True:
        conn,addr = server.accept()
        p = Process(target=talk,args=(conn,))
        p.start()

    server.close()

if __name__ == '__main__':
    server('127.0.0.1',9011)
复制代码

2)client端;编程

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/18/2018 6:37 PM

from socket import *

client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',9011))

while True:
    msg = input('>>>:').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    print(data.decode('utf-8'))
复制代码

14-守护进程

一、守护进程初识;

  • 守护进程会在主进程代码执行结束后就终止;
  • 守护进程内没法再开启子进程,不然抛出异常;AssertionError: daemonic processes are not allowed to have children
复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 8:26 AM
""
"""
守护进程-伴随着父进程而消失;
"""
from multiprocessing import Process
import time
import random

def task(name):
    print('%s is running'%name)
    time.sleep(random.randrange(1,3))

    # p = Process(target=time.sleep,args=(3,))
    # p.start()#AssertionError: daemonic processes are not allowed to have children

if __name__ == '__main__':
    p = Process(target=task,args=('子进程1',))
    p.daemon = True
    p.start()

    p.join()
    print('主进程')

#练习题;
from multiprocessing import Process

import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':
    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True#必定要在p.start()前设置,设置p为守护进程,禁止p建立子进程,而且父进程代码执行结束,p即终止运行
    p1.start()
    p2.start()
    print("main-------")
"""
main-------#只要碰到main,就不会出现123和end123;
456
end456
"""
复制代码

15-互斥锁

一、互斥锁初识;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 8:44 AM
""
"""
互斥锁-互相排斥,好比生活中去卫生间,关上门,其余人必须等待;
互斥锁的原理-把并发改为串行,下降了效率,可是保证了数据安全不错乱;
"""
from multiprocessing import Process,Lock
import time
import random

"""
进程之间数据不共享,可是共享同一套文件系统,因此访问同一个文件,
或同一个打印终端,是没有问题的,而共享带来的是竞争,
竞争带来的结果就是错乱,以下:
"""
def task(name,mutex):#mutex互斥的意思;
    mutex.acquire()#获取锁;
    print('%s 1'%name)
    time.sleep(random.randrange(1,2))
    print('%s 2'%name)
    time.sleep(random.randrange(1,2))
    print('%s 3'%name)
    mutex.release()#释放锁;

if __name__ == '__main__':
    mutex = Lock()#生成锁
    for i in range(3):
        p = Process(target=task,args=('进程%s'%i,mutex))
        p.start()
"""
一、未引入互斥锁
进程0 1
进程1 1
进程2 1
进程0 2
进程1 2
进程2 2
进程0 3
进程1 3
进程2 3
二、引入互斥锁
进程0 1
进程0 2
进程0 3
进程1 1
进程1 2
进程1 3
进程2 1
进程2 2
进程2 3
"""
复制代码

16-模拟抢票

一、初次模拟抢票程序;(多个进程共享同一文件,咱们能够把文件当数据库,用多个进程模拟多我的执行抢票任务)

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 8:55 AM
""
"""
16-模拟抢票
"""
from multiprocessing import Process,Lock
import time
import random
import json

def search(name):
    time.sleep(random.randrange(1,2))
    dic = json.load(open('db.txt','r',encoding='utf-8'))
    print('<%s> 查看到剩余票数[%s]'%(name,dic['count']))

def get(name):
    time.sleep(random.randrange(1,2))#模拟读取数据的网络延迟:
    dic = json.load(open('db.txt','r',encoding = 'utf-8'))
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(2)
        json.dump(dic,open('db.txt','w',encoding='utf-8'))
        print('<%s>购票成功'%name)


def task(name):
    search(name)
    get(name)

if __name__ == '__main__':
    for i in range(10):
        p = Process(target = task,args=('路人%s'%i,))
        p.start()
"""
<路人0> 查看到剩余票数[1]
<路人1> 查看到剩余票数[1]
<路人2> 查看到剩余票数[1]
<路人4> 查看到剩余票数[1]
<路人3> 查看到剩余票数[1]
<路人6> 查看到剩余票数[1]
<路人5> 查看到剩余票数[1]
<路人7> 查看到剩余票数[1]
<路人8> 查看到剩余票数[1]
<路人9> 查看到剩余票数[1]
<路人0>购票成功
<路人1>购票成功
<路人2>购票成功
<路人4>购票成功
<路人3>购票成功
<路人6>购票成功
<路人5>购票成功
<路人7>购票成功
<路人8>购票成功
<路人9>购票成功
"""

#加锁处理:购票行为由并发变成了串行,牺牲了运行效率,但保证了数据安全
from multiprocessing import Process,Lock
import time
import random
import json

def search(name):
    time.sleep(random.randrange(1,2))
    dic = json.load(open('db.txt','r',encoding='utf-8'))
    print('<%s> 查看到剩余票数[%s]'%(name,dic['count']))

def get(name):
    time.sleep(random.randrange(1,2))#模拟读取数据的网络延迟:
    dic = json.load(open('db.txt','r',encoding = 'utf-8'))
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(2)
        json.dump(dic,open('db.txt','w',encoding='utf-8'))
        print('<%s>购票成功'%name)


def task(name,mutex):
    #mutex.acquire()#此处,注意加锁的顺序;
    search(name)
    mutex.acquire()
    get(name)
    mutex.release()
"""
<路人0> 查看到剩余票数[1]
<路人0>购票成功
<路人1> 查看到剩余票数[0]
<路人2> 查看到剩余票数[0]
<路人3> 查看到剩余票数[0]
<路人4> 查看到剩余票数[0]
<路人5> 查看到剩余票数[0]
<路人8> 查看到剩余票数[0]
<路人7> 查看到剩余票数[0]
<路人6> 查看到剩余票数[0]
<路人9> 查看到剩余票数[0]
"""

if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target = task,args=('路人%s'%i,mutex))
        p.start()
"""
<路人2> 查看到剩余票数[1]
<路人0> 查看到剩余票数[1]
<路人3> 查看到剩余票数[1]
<路人7> 查看到剩余票数[1]
<路人1> 查看到剩余票数[1]
<路人6> 查看到剩余票数[1]
<路人5> 查看到剩余票数[1]
<路人8> 查看到剩余票数[1]
<路人9> 查看到剩余票数[1]
<路人4> 查看到剩余票数[1]
<路人2>购票成功
"""
复制代码

17-互斥锁与join的区别

一、互斥锁与join都可以将并发变成串行,为什么还要使用互斥锁呢?

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 9:49 AM
from multiprocessing import Process,Lock
import time
import random
import json

def search(name):
    time.sleep(random.randrange(1,2))
    dic = json.load(open('db.txt','r',encoding='utf-8'))
    print('<%s> 查看到剩余票数[%s]'%(name,dic['count']))

def get(name):
    time.sleep(random.randrange(1,2))#模拟读取数据的网络延迟:
    dic = json.load(open('db.txt','r',encoding = 'utf-8'))
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(2)
        json.dump(dic,open('db.txt','w',encoding='utf-8'))
        print('<%s>购票成功'%name)
    else:
        print('<%s>购票失败'%name)

def task(name,):
    #mutex.acquire()
    search(name)
    #mutex.acquire()
    get(name)
    #mutex.release()
if __name__ == '__main__':
    #mutex = Lock()
    for i in range(10):
        p = Process(target = task,args=('路人%s'%i,))#args传值为元组,带有逗号
        p.start()
        p.join()
"""
<路人0> 查看到剩余票数[1]
<路人0>购票成功
<路人1> 查看到剩余票数[0]
<路人1>购票失败
<路人2> 查看到剩余票数[0]
<路人2>购票失败
<路人3> 查看到剩余票数[0]
<路人3>购票失败
<路人4> 查看到剩余票数[0]
<路人4>购票失败
<路人5> 查看到剩余票数[0]
<路人5>购票失败
<路人6> 查看到剩余票数[0]
<路人6>购票失败
<路人7> 查看到剩余票数[0]
<路人7>购票失败
<路人8> 查看到剩余票数[0]
<路人8>购票失败
<路人9> 查看到剩余票数[0]
<路人9>购票失败
"""

#小结:
"""
一、发现使用join方法后,将并发改成串行,确实能保证数据安全,但问题连查票操做也
变成只能一个一个去查了,很明显,你们查票的时候应该是并发地去查询
而无需考虑数据正确与否,此时join与互斥锁的区别就显而易见了。
二、join是将一个任务总体串行,而互斥锁的好处则是将一个任务中的某一行代码串行,好比只让
task函数的get任务串行;


def task(name,):
    search(name)#并发执行
    
    Lock.acquire()
    get(name)#串行执行
    Lock.release()
"""
复制代码

18-队列的使用

一、队列初识;

进程彼此之间互相隔离,要实现进程间通讯(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的;json

1)建立队列的类(底层就是以管道和锁定的方式实现的)缓存

Queue([maxsize]):建立共享的进程队列,Queue是多进程安全的队列,可使用Queue实现多进程之间的数据传递。

2)Queue的参数介绍;安全

maxsize是队列中容许最大项数,省略则无大小限制。
但须要明确:
    一、队列内存放的是消息而非大数据
    二、队列占用的是内存空间,于是maxsize即使是无大小限制也受限于内存大小

3)主要方法介绍网络

q = Queue(n)
q.put方法用以插入数据到队列中。
q.get方法能够从队列读取而且删除一个元素。

4)队列的使用多线程

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 10:04 AM
""
"""
掌握队列的使用-先进先出的原则
"""
from multiprocessing import Queue

q = Queue(3)#设置队列数为3,注意:队列中不能放置大文件,而应该是精简的消息;
q.put('hello')
q.put({'a':1})
q.put([1,2,3,4])
#q.put(4)
print(q.get())
print(q.get())
print(q.get())

print(q.empty())#清空队列操做;返回值为True;
#print(q.get())#当队列中的数据被取空以后,再次get,程序将一直停留在这里;
复制代码

19-生产者消费者模型

一、为何要使用生产者消费者模型?

生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,若是生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。一样的道理,若是消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题因而引入了生产者和消费者模式。

二、什么是生产者和消费者模式?

这里强调:生产者消费者模式是经过一个容器来解决生产者和消费者的强耦合问题。

生产者和消费者彼此之间不直接通信,而经过阻塞队列来进行通信,因此生产者生产完数据以后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就至关于一个缓冲区,平衡了生产者和消费者的处理能力。

注意:这个阻塞队列就是用来给生产者和消费者解耦的

三、生产者消费者模型实现;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 10:11 AM
""
"""
 19-生产者消费者模型
"""
import time

def producter():
    for i in range(3):
        res = '包子%s'%i
        print('生产者生产了%s'%res)
        consumer(res)


def consumer(res):
    time.sleep(1)
    print('消费者吃了%s'%res)
producter()
"""
生产者生产了包子0
消费者吃了包子0
生产者生产了包子1
消费者吃了包子1
生产者生产了包子2
消费者吃了包子2
"""
"""
#生产者与消费者之间彼此可能等待对方;
#引入生产者消费者模型,在生产者与消费者之间引入一个“容器”,相似于缓存的做用;
#好处之一:解耦合;
#好处之二平衡了消费者和生产者之间的不对等的能力:
"""

from multiprocessing import Process,Queue
import time

def producter(q):
    for i in range(10):
        res = '包子%s'%i
        time.sleep(0.5)#模拟生产消耗的时间
        print('生产者生产了%s'%res)
        q.put(res)

def consumer(q):
    while True:
        res = q.get()
        time.sleep(1)
        print('消费者吃了%s'%res)

if __name__ == '__main__':
    #中间的容器
    q = Queue()
    #生产者
    p1 = Process(target=producter,args=(q,))
    #消费者们
    c1 = Process(target=consumer,args=(q,))
    p1.start()
    c1.start()
    print('主')
"""
主
生产者生产了包子0
生产者生产了包子1
生产者生产了包子2
消费者吃了包子0
生产者生产了包子3
消费者吃了包子1
生产者生产了包子4
生产者生产了包子5
消费者吃了包子2
生产者生产了包子6
生产者生产了包子7
消费者吃了包子3
生产者生产了包子8
生产者生产了包子9
消费者吃了包子4
消费者吃了包子5
消费者吃了包子6
消费者吃了包子7
消费者吃了包子8
消费者吃了包子9

引入了队列的概念,生产者与消费者之间互不影响;但以上会出现消费者持续等待的情景
"""

"""
生产者生产了包子0
生产者生产了包子1
消费者吃了包子0
生产者生产了包子2
生产者生产了包子3
生产者生产了包子4
消费者吃了包子1
生产者生产了包子5
消费者吃了包子2
生产者生产了包子6
生产者生产了包子7
消费者吃了包子3
生产者生产了包子8
生产者生产了包子9
主
消费者吃了包子4
消费者吃了包子5
消费者吃了包子6
消费者吃了包子7
消费者吃了包子8
消费者吃了包子9

Process finished with exit code 0
"""
#生产者有多个;
from multiprocessing import Process,Queue
import time

def producter(q):
    for i in range(10):
        res = '包子%s'%i
        time.sleep(0.5)#模拟生产消耗的时间
        print('生产者生产了%s'%res)
        q.put(res)

def consumer(q):
    while True:
        res = q.get()
        if res is None:break
        time.sleep(1)
        print('消费者吃了%s'%res)

if __name__ == '__main__':
    #中间的容器
    q = Queue()
    #生产者
    p1 = Process(target=producter,args=(q,))
    p2 = Process(target=producter,args=(q,))
    p3 = Process(target=producter,args=(q,))
    p4 = Process(target=producter,args=(q,))
    #消费者们
    c1 = Process(target=consumer,args=(q,))
    c2 = Process(target=consumer,args=(q,))
    c3 = Process(target=consumer,args=(q,))

    p1.start()
    p2.start()
    p3.start()
    p4.start()
    c1.start()
    c2.start()
    c3.start()


    p1.join()
    p2.join()
    p3.join()
    p4.join()
    q.put(None)
    q.put(None)
    q.put(None)
    print('主')
复制代码

20-JoinableQueue的使用

一、引入JoinableQueue([maxsize]);

 

这就像是一个Queue对象,但队列容许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

 

二、JoinableQueue方法介绍;

JoinableQueue的实例p除了与Queue对象相同的方法以外还具备:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。若是调用此方法的次数大于从队列中删除项目的数量,将引起ValueError异常
q.join():生产者调用此方法进行阻塞,直到队列中全部的项目均被处理。阻塞将持续到队列中的每一个项目均调用q.task_done()方法为止

 

三、基于JoinableQueue实现生产者消费者模型;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 11:24 AM
from multiprocessing import Process,JoinableQueue,Queue
import time
import random

def producer(q):
    for i in range(3):
        res = '包子%s'%i
        time.sleep(0.5)
        print('生产了%s'%res)
        q.put(res)
    q.join()
def consumer(q):
    while True:
        res = q.get()
        if res is None:break
        time.sleep(1)
        print('消费者吃了%s'%res)
        q.task_done()

if __name__ == '__main__':
    #容器
    q = JoinableQueue()

    p1 = Process(target=producer,args=(q,))
    p2 = Process(target=producer,args=(q,))
    p3 = Process(target=producer,args=(q,))

    c1 = Process(target=consumer,args=(q,))
    c2 = Process(target=consumer,args=(q,))
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    p3.start()

    c1.start()
    c2.start()

    p1.join()
    p2.join()
    p3.join()
    print('主')
"""
生产了包子0
生产了包子0
生产了包子0
生产了包子1
生产了包子1
生产了包子1
消费者吃了包子0
生产了包子2
消费者吃了包子0
生产了包子2
生产了包子2
消费者吃了包子0
消费者吃了包子1
消费者吃了包子1
消费者吃了包子1
消费者吃了包子2
消费者吃了包子2
消费者吃了包子2
主

Process finished with exit code 0
"""
复制代码

21-什么是线程

一、什么是线程?

在传统操做系统中,每一个进程有一个地址空间,并且默认就有一个控制线程

线程顾名思义,就是一条流水线工做的过程(流水线的工做须要电源,电源就至关于cpu),而一条流水线必须属于一个车间,一个车间的工做过程是一个进程,车间负责把资源整合到一块儿,是一个资源单位,而一个车间内至少有一条流水线。

小结:因此,进程只是用来把资源集中到一块儿(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。

二、什么是多线程?

多线程(即多个控制线程)的概念是,在一个进程中存在多个线程,多个线程共享该进程的地址空间,至关于一个车间内有多条流水线,都共用一个车间的资源。例如,北京地铁与上海地铁是不一样的进程,而北京地铁里的13号线是一个线程,北京地铁全部的线路共享北京地铁全部的资源,好比全部的乘客能够被全部线路拉。

三、线程与进程的区别?

1) 来点儿英文范儿吧!并发

复制代码
一、Threads share the address space of the process that created it; processes have their own address space.
二、Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
三、Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
四、New threads are easily created; new processes require duplication of the parent process.
五、Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
五、Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
复制代码

2)算了,仍是别装13了,直接上中文吧!

  • 同一个进程内的多个线程共享该进程内的地址资源;
  • 建立线程的开销要远小于建立进程的开销(建立一个进程,就是建立一个车间,涉及到申请空间,并且在该空间内建至少一条流水线,但建立线程,就只是在一个车间内造一条流水线,无需申请空间,因此建立开销小);

四、多线程应用举例:

一、开启一个字处理软件进程,该进程确定须要办不止一件事情,好比监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操做的都是同一块数据,于是不能用多进程。
二、只能在一个进程里并发地开启三个线程,若是是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。

 

22-开启线程的两种方式

一、threading模块介绍;

threading与multiprocessing模块很是类似,具体见后者的用法章节;

二、开启线程的两种方式;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 11:53 AM
""
"""
22-开启线程的两种方式
"""
#回顾开进程的方式;
import time
import random
from multiprocessing import Process

def piao(name):
    print('%s piaoing'%name)
    time.sleep(random.randrange(1,3))
    print('%s piao ended'%name)

if __name__ == '__main__':
    p1 = Process(target=piao,args=('cuixiaozhao',))#必须加上,号
    #调用对象下的方法,开启四个进程
    p1.start()
    print('主')

#开启线程的方式1:

import time
import random
from threading import Thread

def piao(name):
    print('%s piaoing'%name)
    time.sleep(random.randrange(1,3))
    print('%s piao ended'%name)

if __name__ == '__main__':
    t1 = Thread(target=piao,args=('cuixiaozhao',))#必须加上,号

    t1.start()
    print('主线程1')

#开启线程的方式2
from threading import Thread
import time

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

    def run(self):#默认必须叫作run
        print('%s in running'%self.name)
        time.sleep(3)
        print('%s is done'%self.name)

if __name__ == '__main__':
    t = MyThread('子线程2')
    t.start()
    print('主线程2')

"""
小结:
一、起线程的两种方式与起进程的两种很是很是类似,几乎如出一辙,就是把multiprocessing换成threading便可
二、明确清楚进程与线程的概念区别:
    同一个进程内的多线线程共享该进程内的地址资源
    建立线程的开销要远小于建立进程的开销(建立一个进程,就是建立一个车间,设计到申请空间,并且在该空间内创建至少与一条流水线(即默认开启一个线程);
    可是建立线程,就是在一个车间内造出一个新的流水线,无需申请基础空间,因此建立开销小)
"""
复制代码

23-进程与线程的区别

一、进程Process与线程Thread的区别;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 12:05 PM
""
"""
23-进程与线程的区别:
一、开进程的开销远大于开线程;
二、同一进程内的多个线程共享该进程的地址空间
"""
#区别1;
import time
import random
from threading import Thread
from multiprocessing import Process
def piao(name):
    print('%s piaoing'%name)
    time.sleep(random.randrange(1,3))
    print('%s piao ended'%name)

if __name__ == '__main__':
    # p1 = Process(target=piao, args=('cuixiaozhao',))
    # p1.start()
    """
    主线程1
    cuixiaozhao piaoing
    cuixiaozhao piao ended
    """
    t1 = Thread(target= piao,args=('cuitianqing',))
    t1.start()
    print('主线程1')
    """
    cuitianqing piaoing
    主线程1
    cuitianqing piao ended
    """

#区别2;
from threading import Thread
from multiprocessing import Process

n = 100
def task2():
    global n
    n = 0

if __name__ == '__main__':
    # p1 = Process(target=task2,)
    # p1.start()
    # p1.join()#等待子进程运行完成,结果为:主线程 100

    t1 = Thread(target= task2,)
    t1.start()#主线程 0
    t1.join()
    print('主线程',n)


#区别3,瞅一眼pid
from threading import Thread
from multiprocessing import Process,current_process
import os

def task3():
    #print(current_process().pid)#7428
    print('子进程PID:%s 父进程的PPID:%s'%(os.getpid(),os.getppid()))#子进程PID:7760 父进程的PPID:19624

if __name__ == '__main__':
    # p1 = Process(target= task3,)
    # p1.start()
    t1 = Thread(target=task1,)
    t1.start()
    #print('主线程',current_process().pid)#主线程 19664
    print('主进程',os.getpid())#主进程 7760


#区别4,瞅一眼pid
from threading import Thread
import os

def task4():
    print('子线程PID:%s '%(os.getpid()))#子线程PID:12248

if __name__ == '__main__':
    t1 = Thread(target=task4,)
    t1.start()
    print('主线程',os.getpid())#主线程 12248

#注意:其实没有子线程PID,线程都是相同级别的,你们地位相等,为了便于理解,才在此处称之为:子线程;
复制代码

24-Thread对象的其余属性或方法

一、方法介绍;

复制代码
Thread实例对象的方法
  # isAlive(): 返回线程是否活动的。
  # getName(): 返回线程名。
  # setName(): 设置线程名。

threading模块提供的一些方法:
  # threading.currentThread(): 返回当前的线程变量。
  # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
复制代码

二、方法验证;

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 5:12 PM
from threading import Thread,current_thread,active_count,enumerate
import time

def task():
    print('%s is runing'%current_thread().getName())
    time.sleep(2)
    print('%s is done'%current_thread().getName())

if __name__ == '__main__':
    t = Thread(target= task,name='子线程1')
    t.start()
    #t.setName('儿子线程1')
    #current_thread().setName('主线程')
    #print(t.is_alive())#返回值为True或者False
    #print(t.isAlive())#返回值为True或者False
    #print(t.getName())
    #print('主线程',current_thread().getName())
    #t.join()
    print(active_count())
    print(enumerate())#[<_MainThread(MainThread, started 10096)>, <Thread(子线程1, started 14432)>]
复制代码

25-守护线程

一、守护线程初识;

不管是进程仍是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁;

1)须要强调的是:运行完毕并不是终止运行;

一、对主进程来讲,运行完毕指的是主进程代码运行完毕;

二、对主线程来讲,运行完毕指的是主线程所在的进程内全部非守护线程通通运行完毕,主线程才算运行完毕;

2)详细解释;

一、主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),而后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(不然会产生僵尸进程),才会结束;

二、主线程在其余非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。由于主线程的结束意味着进程的结束,进程总体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束;

3)验证一下吧!

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 5:27 PM
""
"""
 25-守护线程
"""
from threading import Thread
import time

def sayhi(name):
    time.sleep(1)
    print('%s say hello'%name)

if __name__ == '__main__':
    t = Thread(target= sayhi,args= ('cuixiaozhao',))
    #t.setDaemon(True)#必须在t.start()以前设置;
    t.daemon = True #做用同上;
    t.start()

    print('主线程')
    #print(t.isAlive())
    print(t.is_alive())#做用同上;


from threading import Thread
import time

def foo():
    print(123)
    time.sleep(1)
    print('end123')

def bar():
    print(456)
    time.sleep(3)
    print('end456')
"""
123
456
--------main--------
end123
end456
"""

if __name__ == '__main__':
    t1 = Thread(target= foo)
    t2 = Thread(target=bar)

    t1.daemon = True
    t1.start()
    t2.start()
    print('main'.center(20,'-'))
复制代码

26-互斥锁

一、互斥锁概念再次初识;

 

复制代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:7/20/2018 5:47 PM
""
"""
 26-互斥锁-由并行改成串行,牺牲了性能,保证了数据安全;
 
"""
#mutex
from threading import Thread,Lock
import time

n = 100
def task():
    global n
    mutex.acquire()
    temp = n
    time.sleep(0.1)
    n = temp -1
    mutex.release()

if __name__ == '__main__':
    mutex = Lock()#局部加锁
    t_l = []
    for i in range(100):
        t = Thread(target= task,)
        t_l.append(t)
        t.start()

    for t in t_l:
        t.join()
    print('主',n)
"""
小结:
一、牺牲了效率;
二、保证了数据安全;
"""
复制代码

 

27-GIL的基本概念

28-GIL与互斥锁的区别

29-GIL与多线程

30-死锁与递归锁

31-信号量

32-Event事件

33-定时器

34-线程queue

35-多线程实现并发的套接字通讯

36-进程池线程池

37-异步调用与回调机制

38-进程池线程池小练习

39-协程介绍

40-greenlet模块

41-greenlet模块

42-gevent模块

43-gevent异步提交任务

44-基于gevent模块实现并发的套接字通讯

45-IO模型介绍

46-阻塞IO模型

47-非阻塞IO模型

48-多路复用IO模型

49-异步IO模型

相关文章
相关标签/搜索