目录:


一、线程

    1.线程基本操作 

        1.创建线程的方式

        2.线程锁

        3.信号量以及事件

        4.条件以及定时器

    2.队列的使用

        1.队列的使用

        2.生产者消费者模型

    3.自定义线程池


二、进程   

    1.进程基本操作

        1.创建进程

        2.进程锁

    2.进程池


三、协程

   1.greenlet

    2.gevent


四、缓存    

    1.python操作memcache

    2.python操作redis

一、线程

    

  1.线程基本操作

      1.创建线程的方式

#创建线程方法一(最常见)
import threading

def f1(args):
    print(args)
t = threading.Thread(target=f1,args=(123,))
t.start()   #线程开启,等待cpu调用

'''
t.run() 方法:
    当cpu调度的时候,就执行Thread里边的run方法
    t.run() #是由cpu替我们调度执行的
'''

#创建线程方法二 (通过创建类创建线程) (自定义方式)
import threading
class MyThread(threading.Thread):
    def __init__(self,func,args): #定义init,就不执行父类的方法了,执行自己的
        self.func = func
        self.args = args
        super(MyThread,self).__init__()
    def run(self):
        self.func(self.args)

def f2(arg):
    print(arg)
obj = MyThread(f2,123)            #func = f2  args=123
obj.start()

      2.线程锁(同时只允许一个线程进入取值。)

线程锁分类:
    1.
        l.acquire()
        l.release()
        lock = threading.Lock()     #只能锁一次
    2.
        l.acquire()
        l.release()
        lock = threadingRLock()    #可以递归锁,可以锁多层,可以嵌套。 (常用)

例子:
当有一个数字10,如果同时10个线程去减1,
那么就会产生脏数据,输出结果都输出为0。

#例1
import threading
import time
NUM = 10

def func(l):
    global NUM
    NUM -= 1
    time.sleep(2)           #会产生脏数据,造成输出都是0
    print(NUM)
lock = threading.Lock()     #只能锁一次
for i in range(10):
    t = threading.Thread(target=func,args=(lock,))
    t.start()

#解决此问题就是加锁,同时只允许一个线程进入取值。;(单层锁)
#例2
import threading
import time
NUM = 10

def func(l):
    global NUM
    l.acquire()             #上锁 使同一时刻只有一个进程使用
    NUM -= 1
    time.sleep(2)           #会产生脏数据,造成输出都是0
    print(NUM)
    l.release()             #开锁
lock = threading.Lock()     #只能锁一次
for i in range(10):
    t = threading.Thread(target=func,args=(lock,))
    t.start()
    
#例3 多层锁
import threading
import time
NUM = 10

def func(l):
    global NUM
    #上锁               #使同一时刻只有一个进程使用
    l.acquire()
    NUM -= 1
    l.acquire()     #多层锁
    time.sleep(2)       #会产生脏数据,造成输出都是0
    l.release()     #多层锁
    print(NUM)
    l.release()     #开锁
#lock = threading.Lock()     #只能锁一次
lock = threading.RLock()    #可以递归锁,可以锁多层,可以嵌套。
for i in range(10):
    t = threading.Thread(target=func,args=(lock,))
    t.start()

      3.信号量以及事件

信号量(semaphore)(同时允许一定数量的线程更改数据)

#例1 信号量(semaphore)(同时允许一定数量的线程更改数据)
import threading
import time
NUM = 10

def func(i,l):
    global NUM
    #上锁             #使同一时刻只有一个进程使用
    lock.acquire()       #一次放5个出去
    NUM -= 1
    time.sleep(2)       #会产生脏数据,造成输出都是0
    print(NUM,i)
    #开锁
    lock.release()
lock = threading.BoundedSemaphore(5)
for i in range(30):
    t = threading.Thread(target=func,args=(i,lock,))
    t.start()
    
#例2 事件(event)(事件用于主线程控制其他线程的执行,相当于红绿灯。主要有三个方法:set、wait、clear)
#批量将所有线程挡住,改一个标识,全部放走
#内部就是维护了一个状态,默认是False,改成True就能走了 。
#输出结果顺序不一样,是因为线程调度事件不一样
import threading

def func(i,e):
    print(i)
    e.wait()        #表示它在这等待;检测是什么灯,如果是红灯就停;
    print(i+100)
event = threading.Event()
for i in range(10):
    t = threading.Thread(target=func,args=(i,event,))
    t.start()
#==========
event.clear()       #主动设置成红灯就是False,默认是False
inp = input(">>")
if inp == "1":     #当输入1的时候就继续
    event.set()     #把上边的红灯设置成绿灯,将Flag设置为True

      4.条件以及定时器

条件Condition (使得线程等待,只有满足某条件时,才释放n个线程)

#例1: 当输入数字等于几时,那么久释放几个线程过去。
import threading

def run(n):
    con.acquire()       #配合下边wait使用
    con.wait()          #在这里等着了
    print("run the thread: %s" %n)
    con.release()

if __name__ == '__main__':

    con = threading.Condition()     #创建条件
    for i in range(10):
        t = threading.Thread(target=run, args=(i,))
        t.start()

    while True:
        inp = input('>>>')
        if inp == 'q':
            break
        #以下三行是固定用法
        con.acquire()
        con.notify(int(inp))
        con.release()
        
#当条件满足之后,出去一个,再满足,再出去一个
#例2     当满足条件,输入true,那么就i+100 ,再输入true 下个数再加100
import threading
def condition():
    ret = False
    r = input(">>>>")
    if r == 'true':
        ret = True
    else:
        ret = False
    return ret

def func(i,con):
    print(i)
    con.acquire()   #配合下边wait使用
    con.wait_for(condition)  #在这里等着了
    print(i+100)
    con.release()

c = threading.Condition()
for i in range(10):
    t = threading.Thread(target=func,args=(i,c,))
    t.start()
    
#定时器 Timer   (定时器,指定n秒后执行某操作)
#例3
#1秒钟之后执行某函数
#应用到写客户端、监控的时候。

from threading import Timer

def hello():
    print("hello world")

t = Timer(1,hello)    #1秒钟之后执行
t.start()

  2.队列的使用(Python中队列是线程间最常用的交换数据的形式

1.queue队列
    基本特点:
        先进先出
    方法:
        put         放数据,是否阻塞,阻塞时的超时时间
        get         取数据,默认阻塞,是否阻塞,阻塞时的超时时间
        q.empty     检查队列是否为空,为空返回True,否则False
        q.full      判对是否满了
        q.qsize     队列里边有几个元素;当前真实个数
        q.maxsize   元素最大支持的个数
        q.join      如果队列任务没有完成,还在等待。
        q.taskdone  每一次取完数据的时候执行q.task_done(),告诉我执行完了,系统做一个计数。表示我取完数据了
        join,task_done 阻塞进程,当队列中任务执行完毕之后,不再阻塞。
2.其他队列:
    1、后进先出
        queue.LifoQueue
    2、优先级队列 (放数据的时候加上权重值;内容包括:数据+权重)
        queue.PriorityQueue
    3、双向队列    (两边存、两边取)
        queue.deque

import queue        #导入队列模块

q = queue.Queue(10)          #创建一个队列;参数10代表最多接收10个数据。放不进去就等着或者报错
q.put(11,timeout=2)          #放数据;timeout=2 代表等待2秒,如果还没有位置就报错;有位置就加进去
q.put(22,block=False)       #默认block是阻塞等待,只要没有位置就等待;如果改成True,就不等待,直接报错
q.put(33)
print(q.qsize())             #显示当前多少数据
print(q.get(block=False))   #取数据;默认是阻塞,默认情况下没有数据的时候就一直等待,
print(q.empty())             #检查队列是否为空,为空返回True,否则False
#输出
    3
    11
    False

q = queue.Queue(5)
q.put(33)
q.put(44)
print(q.get())
print(q.task_done())
print(q.get())
print(q.task_done())
#输出:
    33
    None
    44
    None
#每一次取完数据的时候执行q.task_done(),告诉我执行完了,系统做一个计数。表示我取完数据了
#q.join()    #如果队列任务没有完成,还在等待。

#queue.LifoQueue    特点:后进先出
q = queue.LifoQueue()
q.put(123)
q.put(456)
print(q.get())      #456是后进去的,先取出来
#输出:
    456

#queue.PriorityQueue    特点:优先级队列
q = queue.PriorityQueue()
q.put((1,'aaa'))
q.put((2,'bbb'))
print(q.get())      #按照优先级取数据,如果优先级相同,谁先放,先取谁
#输出:
    (1, 'aaa')

#queue.deque    特点:双向队列(两边都可以取数据,都可以放数据)
q =queue.deque()
q.append(123)
q.append(456)
q.appendleft(333)   #左边放数据
print(q.pop())      #取数据,默认取最右边的
print(q.popleft())  #左边取数据
#输出:
    456
    333

  3.自定义线程池