thread

 

进程间通信之共享内存
通信原理:在内存空间开辟一个区域,对多个进程可见,进程可以写入内容
或读取内容,但是每次写入的内容会覆盖之前的内容
from multiprocessing import Value,Array

obj = Value(ctype,obj) (只能存单个数据)
功能:开辟共享内存空间
参数:ctype 字符串,表示共享内存中要存储的数据类型
常用类型:int--->'i'
float--->'f'
char(bytes)---->'c'
obj 共享内存中放入的初始化数据

obj.value 对该属性的修改和使用即对共享内存数据的修改使用

obj = Array(ctype,obj)
功能:创建共享内存
参数:ctype 要存储的而数据类型
obj 存入一个结构化的数据(列表,bytes字符串)表示共享内存中的初始数据
传入正整数 则表示在共享内存中开辟指定大小的数据空间
返回值: 共享内存对象
* 可以通过遍历可以获取每个值,支持索引操作
例如: obj[2] 表示获取共享内存中第三项,对其修改即对共享内存修改
* 如果存入的是字符串,可以通过obj.value直接打印整个字符串

管道 消息队列 共享内存
开辟空间 内存 内存 内存
读写方式 两端读写 先进先出 覆盖之前的内容
效率 一般 一般 较高
特点 多用于父子进程 有很多第三方队列 需要注意同步操作

信号量(信号灯)
原理:给定一个数量,多个进程均可见,多个进程可以通过方法操作数量,达到协同工作的目的
from multiprocessing import Semaphore
sem = Semaphore(num)
功能:创建信号量对象
参数:信号量的初始值
返回值:信号量对象

sem.acquire() 将信号量减1 当信号量为0时会阻塞
sem.release() 将信号量加1
sem.get_value() 获取信号量数量

多任务编程之线程(Thread)
什么是线程?
1.线程也是多任务编程方法
2.也可以使用计算机的多核资源
3.线程被成为轻量级的进程
4.线程是系统分配内核的最小工作单元
线程特征
1.一个进程可以包含多个线程
2.线程是一个运行的过程,需要消耗计算机资源
3.多个线程的执行相互不影响不干扰
4.线程的创建销毁,消耗的资源远远小于进程
5.一个进程中的多个线程,共享这个进程的系统资源
6.每个线程也有自己特有的特征,比如ID,指令集等

threading 模块创建线程
from threading import Thread

t = Thread()
功能: 创建线程对象
参数:target 绑定线程函数
args 元组 给线程函数位置传参
kwgars 字典 给线程函数键值对传参
name 线程名称 默认为Thread-1

t.start() 启动线程,自动运行线程函数
t.join([timeout]) 回收线程

线程对象属性
t.name 线程名称
t.setName() 设置名称
t.getName() 获取名称
t.is_alive() 线程状态

threading.currentThread() 在线程函数中获取当前线程对象
t.daemon 默认为False此时主线程退出,分支线程会继续执行
如果设置为True则主线程退出,分支线程也随之退出

t.setDaemon(True) 设置daemon属性
t.isDaemon() 判断daemon的值
* 在start前设置,通常不和join同用

创建自己的线程类
步骤:
1.继承Thread
2.添加自己属性写__init__,加载父类init
3.重写run方法
4.使用自己的类生产线程对象,调用start启动线程,此时会自动运行run方法作为线程执行

线程间通信
通信方法:
使用进程空间中全局变量通信
注意事项:共享资源的争夺,往往需要同步互斥机制协调

线程的同步互斥
共享资源(临界资源):多个线程都可以操作的资源称为共享资源
临界区:指一段代码段,对临界资源操作的代码段称为临界区

同步:同步是指一种合作关系,为完成任务,多进程或者线程之间形成一种协调,按照必要的步骤
有序执行操作临界资源

互斥:互斥是一种制约关系,当一个进程或者线程使用临界资源时会进行加锁处理,此时另一个进程
或者线程就无法操作临界资源,直到解锁后才能操作

线程的同步互斥方法:
线程 Event
from threading import Event
e = Event() #创建线程Event对象
e.wait([timeout])
功能:阻塞函数,等待e被设置
参数:超时时间
e.set() 将e变为设置状态
e.clear() 将e变回未设置状态
e.is_set() 判断当前e的状态,被设置得到True否则False

线程锁 Lock
from threading import Lock
lock = Lock() 创建锁对象
lock.acquire() 上锁  如果已经上锁调用此函数会阻塞
lock.release() 解锁  

with lock 上锁操作
....
....
 with 语句块结束自动解锁

python线程的GIL问题  (全局解释器锁)
GIL:由于python解释器设计中加入了解释器锁,导致python解释器在同一时刻只能解释一个线程,
所以大大降低了python的执行效率

后果:python线程一般会用在存在大量阻塞的IO  程序或者高延迟的IO程序中(网络消息收发)
因为python线程在遇到阻塞时会主动让出解释器

GIL建议解决:
*尽量使用进程完成并发
*不使用c作为解释器   用java c#
* 可以使用多种组合的并发方案

from threading import Thread,Event
from time import sleep

s = None #作为通信变量
e = Event()

def bar():
print("Bar 拜山头")
global s
s = '天王盖地虎'
e.set()

b = Thread(target = bar)
b.start()

# sleep(2)
print("说对口令就是自己人")
e.wait() #阻塞等待,分支线程设置e.set()
if s=='天王盖地虎':
print("确认过眼神,你是对的人")
else:
print("打死他")
e.clear()

b.join()
 
from threading import Thread,Lock

a=b=0
lock = Lock() #锁对象
def value():
while True:
lock.acquire()
if a != b:
print("a = %d,b = %d"%(a,b))
lock.release()

t = Thread(target = value)
t.start()

while True:
with lock:
a += 1
b += 1

t.join()
 
from threading import Thread,Lock

a=b=0
lock = Lock() #锁对象
def value():
while True:
lock.acquire()
if a != b:
print("a = %d,b = %d"%(a,b))
lock.release()

t = Thread(target = value)
t.start()

while True:
with lock:
a += 1
b += 1

t.join()
 



from multiprocessing import Process,Value
import time
import random

#创建共享内存
money = Value('i',10000)

#操作共享内存增加
def man():
for i in range(30):
time.sleep(0.2)
#对Value属性操作即对共享内存操作
money.value +=random.randint(1,1000)

def girl():
for i in range(30):
time.sleep(0.16)
money.value -=random.randint(100,900)

m = Process(target = man)
g = Process(target = girl)

m.start()
g.start()

m.join()
g.join()

print('一个月余额:',money.value)
posted @ 2019-04-16 22:00  全宇宙第一帅  阅读(353)  评论(0编辑  收藏  举报