wcleonard

导航

 
前情回顾:

1.进程间通信

管道 Pipe recv send
消息队列 Queue get put qsize full empty
共享内存 效率高 Value shm.value Array shm迭代
信号 : 异步通信 kill alarm pause
信号量 套接字

2. 进程池 Pool apply_async apply close join
map

3. 创建进程类 重写run

***********************************************
信号处理 :

signal.signal(signum,handler)
功能 : 处理一个信号
参数 : signum : 要处理的信号
handler : 对该信号的处理方法
SIG_DFL 采用默认方法
SIG_IGN 忽略这个信号
func 自定义的方法处理
func 格式要求

def func(sig,frame):
....
sig : 接收到的信号
frame : 信号对象


* signal函数是一个异步处理信号函数,只要执行,在进程中就会按照指定方法处理信号
* signal 不能处理 SIGSTOP SIGKILL信号


信号量 : 给定一定的信号数量,对多个进程可见,并且多个进程均可操作。进程根据信号量的多少,可以有不同的行为

multiprocess ----》 Semaphore()

sem = Semaphore(num)
功能 : 定义信号量
参数 : num : 给定信号量的初始个数
返回值 : 返回信号量对象

sem.acquire() 将信号量 减一 信号量为0时调用会阻塞

sem.release() 将信号量 加一

cookie :

获取当前进程对象
multiprocssing.current_process()

使用处理僵尸进程
在父进程中,忽略子进程的发送信号
signal(SIGCHLD,SIG_IGN)


同步和互斥

目的 : 对共有资源的操作会产生争夺,同步互斥是一种解决争夺的方案

临界资源 : 多个进程或者线程都可以操作的资源
临界区 : 操作临界资源的代码段

同步 : 同步是一种合作关系,为完成某个任务多进程或者多线程之间形成一种协调 ,按照条件次序执行,传递告知资源情况。 这种协调可能是因为阻塞关系达成的

互斥 :互斥是一种制约关系,但一个进程或线程进入到临界区会进行加锁操作,此时其他进程(线程)在企图操作临界资源就会阻塞。只有当资源被释放才能进行操作

Event 事件

创建 事件对象
e = Event()

提供事件阻塞
e.wait()

对事件对象进程设置,此时wait判断如果事件被set则结束阻塞
e.set()

清除对该事件对象的set
e.clear()

监测对象是否被设置 设置返回True
e.is_set()

锁 Lock

multiprocessing ----》 Lock

lock = Lock()

lock.acquire() 上锁
lock.release() 解锁

with lock: ---》 给with代码段上锁
....
....

-----------------> with 代码段结束自动解锁

* 在lock对象处于上锁状态的时候,再企图上锁则会阻塞
直到锁被释放,才能继续执行上锁操作


线程

* 线程也是所任务编程的一种方法,可以使用计算机多核资源。是计算机核心分配的最小单位
* 线程又称为轻量级的进程,在创建和删除时消耗的计算机资源小

线程和进程关系
* 一个进程中可以包含多个线程
* 进程中的所有线程共享进程的空间资源 (空间,全局变量,分配的内存等)
* 线程也有自己的特有属性,比如 指令集 TID等

创建线程
import threading

threading.Tread

Thread()
功能 : 创建线程
参数 : target 线程函数
args 元组 给线程函数位置传参
kwargs 字典 给线程函数字典传参
name 给线程取名字 (默认Thread-1)
返回 : 线程对象

t.start() 启动线程
t.join(timeout) 回收线程

t.is_alive() 查看线程状态
t.name 查看线程名称
threading.currentThread() 得到线程对象
t.setName() 设置线程名称

t.daemon 属性
默认 为False 主线程执行完毕不会影响分支线程的执行
如果设置为True 则主线执行完毕其他线程也会终止

t.isDaemon() : 判断 daemon属性是True or False

设置方法:
t.daemon = True
t.setDaemon(True)


线程的通信

通过全局变量进行通信

进程和线程的区别和联系
1. 两者都是多任务编程方式,均可使用计算机的多核
2. 进程的创建要比线程消耗更多的资源
3. 进程空间独立,数据安全性更好操作,有专门的进程间通信方式
4. 线程使用全局变量通信,往往要和同步互斥机制配合防止产生资源的争夺
5.一个进程可以包含多个线程,线程共享进程资源。
6. 进程线程都有自己的特有资源。

使用场景 :
需要创建较多的并发,任务比较简单,线程比较合适。
如果程序见数据资源使用重叠比较多,要考虑到线程锁是否需要更复杂的逻辑
如果多个任务并无什么关联性,不易用多线程将其融入到一个进程中
python线程不适用于计算密集型并发


创建自定义线程类 :

1.继承Thread类
2.重写 run 方法


线程中同步互斥方法
Event 线程事件
e = Event()
e.wait() e.set() e.clear()

Lock 线程锁
lock = Lock() 创建锁
lock.acquire() 加锁
lock.release() 解锁

作业 :
信号通信
司机和售票员的故事
1. 创建父子进程,分别表示司机和售票员
2. 当售票员捕捉到 SIGINT信号时 给司机发送 SIGUSER1信号, 此时司机打印 “老司机开车了”
当售票员捕捉到 SIGQUIT时 给司机发送 SIGUSER2信号,此时司机打印“系好安全带,车速有点快”
当司机捕捉到 SIGTSTP时,发送SIGUSER1给售票员,售票员打印 “到站了,请下车”
3. 到站后 售票员先下车(子进程退出),然后司机下车

温馨提示 : 键盘发送信号会给终端所有进程


TFTP文件服务器

文件的上传,下载,和服务端文件库的查看

服务端 客户端
1.查看文件库中有哪些文件
2.下载文件到本地
3.将本地的文件上传到文件库

***************************************************************
from multiprocessing import Event

#创建事件对象
e = Event()

print(e.is_set())

e.set()

e.wait()

print(e.is_set())

#将设置清除 wait又阻塞
e.clear()

e.wait()

****************************************************************
from threading import Thread
from time import ctime,sleep

#编写自己的线程类
class MyThread(Thread):
def __init__(self,func,args,name = "Tedu"):
super().__init__()
self.func = func
self.args = args
self.name = name

# 调用start会自动运行
def run(self):
self.func(*self.args)

def player(file,sec):
for i in range(2):
print("playing %s : %s"%(file,ctime()))
sleep(sec)


t = MyThread(player,('baby.mp3',3))
t.start()
t.join()

******************************************************************
from multiprocessing import Event,Process
from time import sleep

def wait_event():
print("process1也想操作临界区,但是要阻塞等待主进程")
e.wait()
print("主进程操作完了,轮到我了",e.is_set())

def wait_event_timeout():
print("process2也想操作临界区,但是要阻塞等待主进程")
e.wait(2)
print("我等不了了,还是执行别的吧",e.is_set())


e = Event()

p1 = Process(name = 'block',target = wait_event)
p2 = Process(name = 'non-block',\
target = wait_event_timeout)

p1.start()
p2.start()

print("假设正在忙碌的操作临界资源")
sleep(3)
e.set()
print("主进程操作完了,开放临界区")

p1.join()
p2.join()

**************************************************************
from multiprocessing import Process,Lock
import sys
from time import sleep

#sys.stdout为所有进程的共有资源
def worker1():
lock.acquire() #上锁
for i in range(5):
sleep(1)
sys.stdout.write("worker1 输出\n")
lock.release() #解锁

def worker2():
#with方式上锁
with lock:
for i in range(5):
sleep(1)
sys.stdout.write("worker2 输出\n")

#创建Lock对象
lock = Lock()

w1 = Process(target = worker1)
w2 = Process(target = worker2)

w1.start()
w2.start()

w1.join()
w2.join()

**************************************************************
from multiprocessing import \
Semaphore,Process,current_process
from time import sleep

#创建信号量初始值为3
sem = Semaphore(3)

def fun():
print("进程 %s 等待信号量"%current_process())
#第四个进程无信号资源会阻塞
sem.acquire()
print("进程 %s 消耗信号量"%current_process())
sleep(3)
print("进程 %s 添加信号量"%current_process())
sem.release()

jobs = []
for i in range(4):
p = Process(target = fun)
p.start()
jobs.append(p)

for i in jobs:
i.join()

**************************************************************
import signal
from time import sleep

signal.alarm(5)

#采用默认的方法处理SIGALRM信号
# signal.signal(signal.SIGALRM,signal.SIG_DFL)

#忽略信号
signal.signal(signal.SIGALRM,signal.SIG_IGN)
signal.signal(signal.SIGINT,signal.SIG_IGN)

while True:
sleep(2)
print("让你摁ctrl + c")
print("等待时钟....")

**************************************************************
from signal import *
import time

#固定格式要求
def handler(sig,frame):
if sig == SIGALRM:
print("收到时钟信号")
elif sig == SIGINT:
print("就不结束")

alarm(7)

#通过自定义方法处理
signal(SIGALRM,handler)
signal(SIGINT,handler)

while True:
print("waiting for a signal")
time.sleep(2)

**************************************************************
import threading
from time import sleep

#线程函数
def music():
while True:
sleep(2)
print("播放葫芦娃")

#创建线程和函数music关联
t = threading.Thread(target = music)
#启动线程
t.start()

while True:
sleep(1.5)
print("想听灌篮高手")

#等待回收线程
t.join()
print("+++++++++++++++++++")

**************************************************************
#线程对象属性
from threading import Thread,currentThread
from time import sleep

def fun(sec):
print("线程属性测试")
sleep(sec)
print(" %s 线程结束"%currentThread().getName())

thread = []
for i in range(3):
t = Thread(name = "tedu" + str(i),\
target = fun,args = (3,))
t.start()
thread.append(t)

for i in thread:
i.join()
print("thread name:",i.name)
print("alive:",i.is_alive())

**************************************************************
#daemon属性
from threading import Thread
from time import sleep

def fun():
print("Daemon 属性测试")
sleep(5)
print("线程结束")

t = Thread(target = fun)

#为线程设置名字
t.setName("tedu")

#daemon属性设置为True
#t.daemon = True
t.setDaemon(True)
print(t.isDaemon())

t.start()
t.join(2)
print("=====主线程结束======")

**************************************************************
import threading
from time import sleep

s = None

#创建线程事件对象
e = threading.Event()

def bar():
print("呼叫foo")
global s
s = "天王盖地虎"

def foo():
print("等待口令")
sleep(2)
if s == "天王盖地虎":
print("foo收到:",s)
else:
print("打死他")
e.set()

def fun():
print("呵呵...")
sleep(1)
e.wait()
global s
s = "小鸡炖蘑菇"


t1 = threading.Thread(name = 'bar',target = bar)
t2 = threading.Thread(name = 'foo',target = foo)
t3 = threading.Thread(name = 'fun',target = fun)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()

**************************************************************
from threading import Thread
from time import sleep

#通过全局变量进行线程通信
a = 1

def foo():
global a
a = 1000

def bar():
sleep(1)
print("a =",a) # a = 1000

t1 = Thread(target = foo)
t2 = Thread(target = bar)

t1.start()
t2.start()

t1.join()
t2.join()

**************************************************************
import threading

a = b = 0

lock = threading.Lock()

def value():
while True:
lock.acquire()
if a != b:
print("a = %d,b = %d"%(a,b))
lock.release()

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

while True:
lock.acquire()
a += 1
b += 1
lock.release()

t.join()
posted on 2018-05-31 21:35  wcleonard  阅读(261)  评论(0编辑  收藏  举报