主线程 bsp sleep 并行 logs 管理 conf 明显
一,回顾操作系统的概念
操作系统位于底层硬件与应用软件之间的一层
工作方式:向下管理软件,向上提供接口
二,进程线程的概念
进程是一个资源单位,线程是一个最小的执行单位
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
三,并行与并发
并行:
就是有多个进程可以同时运行的叫做并行
并发:
就是在一个处理器的情况下,切换执行,叫做并发
python 无法实现并行处理,因为全局解释器锁 gil 导致同一时刻同一进程
只能有一个线程被运行。
GIL 全局解释器锁
但是不影响 Python 开多进程
多线程代码示例
- import threading
- import time
- '''
- 程序在运行是有一个主线程,当程序开启多线程的时候,主线程依旧会执行,
- 主线程执行到最后时,并没有结束,而是在等待子线程的结束后主线程结束
- '''
- def misc():
- print("听歌")
- time.sleep(3)
- print("听歌结束")
- def xieboke():
- print("写博客")
- time.sleep(5)
- print("写博客结束")
- #开启线程
- t1=threading.Thread(target=misc)#t1,t2是一个线程对象
- t2=threading.Thread(target=xieboke)
- t1.start()
- t2.start()
- print("主线程")
#开启多线程的另一种方式
- import threading
- import time
- class MyThread(threading.Thread):
- '''
- 用类的继承,继承线程的方法开启线程
- '''
- def __init__(self,num):
- '''
- 继承父类的__init__方法
- '''
- threading.Thread.__init__(self)
- self.num=num
- def run(self):
- print("running on mythread:%s"%self.num)
- time.sleep(3)
- print("end%s"%self.num)
- t1=MyThread(10)
- t2=MyThread(20)
- t1.start()
- t2.start()
- print("主线程")
jion 的使用
t.jion 方法会阻塞主进程的运行, 但不会影响其他线程的运行
setDaemon 方法
- 守护线程
当某个线程设置为守护线程的时候,它会随着主线程的结束而结束
t.setDaemon(True)
线程对象下的几个方法:
-isAlive()检测线程是否活动,返回值是布尔值
-getName(): 返回线程名
-setName(): 设置线程名称
threading 模块提供的一些方法:
threading.currentTread(): 返回当前线程变量
threading.enumerate(): 返回一个包含正在运行的线程的 list。
threading.activeCount(): 返回正在运行的线程数量
Python 对于计算密集型运行比较慢,效率低;对于 IO 密集型效率有明显提高
Python 多线程
互斥锁:
互斥锁的意义就是在保护锁内代码同一时间只有一个线程在使用
直到代码执行完成,解锁后其他线程才能执行所内代码。
使用格式:
-lock=threading.Lock() 创建一把锁的对象
lock.acquire()# 加锁
.... 需要保护的执行语句
lock.release()# 解锁
死锁与递归锁
代码示例:
- import threading
- import time
- muteA=threading.Lock()
- muteB=threading.Lock()
- class MyThread(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- def run(self):
- self.func1()
- self.func2()
- def func1(self):
- muteA.acquire()
- print("锁A执行内容",MyThread.getName(self))
- muteB.acquire()
- print("锁B执行内容",MyThread.getName(self))
- muteB.release()
- muteA.release()
- def func2(self):
- muteB.acquire()
- print("第二个函数的锁B",MyThread.getName(self))
- muteA.acquire()
- print("第二个函数的锁A",MyThread.getName(self))
- muteA.release()
- muteB.release()
- if __name__=="__main__":
- for i in range(10):
- my_thread=MyThread()
- my_thread.start()
形成死锁的原因在于当线程 1 在第二个函数中拿到锁 B 向下执行需要锁 A 的时候,线程 2 在函数 1 中
已经拿到的锁 A,在等待线程 1 释放 B。两个线程都没有释放另一个线程需要的锁,所以就形成了死锁。
递归锁的应用
递归锁未避免死锁的产生,在锁内实行一个引用计数,当有一把使用是计速器加一,释放后,去除计数
到代码在执行锁内代码时,如果有其他线程抢锁,计数如果为零,线程可以拿到锁,大于零,拒绝线程拿锁
这样就能避免锁的重复,也就不会产生死锁
代码示例:
import threading
import time
Rlock=threading.Rlock()
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
self.func1()
self.func2()
def func1(self):
Rlock.acquire()
print("锁 A 执行内容",MyThread.getName(self))
Rlock.acquire()
print("锁 B 执行内容",MyThread.getName(self))
Rlock.release()
Rlock.release()
def func2(self):
Rlock.acquire()
print("第二个函数的锁 B",MyThread.getName(self))
Rlock.acquire()
print("第二个函数的锁 A",MyThread.getName(self))
Rlock.release()
Rlock.release()
if __name__=="__main__":
for i in range(10):
my_thread=MyThread()
my_thread.start()
event 方法使用:
event 方法可以让两个线程之间通信,当一个线程需要另一个线程准备数据的时候,
event.wait(), 阻塞程序的运行,直到另一个线程将数据准备完成后,使用 event.set()
返回一个 true 值,event.wait() 接受到该值之后,线程开始运行。wait 方法后可以接一个超时
时间参数,规定在一定时间内阻塞,超时后运行。
import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',)
def worker(event):
logging.debug('Waiting for redis ready...')
while not event.isSet():
logging.debug("wait.......")
event.wait(3) # if flag=False 阻塞,等待 flag=true 继续执行
logging.debug('redis ready, and connect to redis server and do some work [%s]', time.ctime())
time.sleep(1)
def main():
readis_ready = threading.Event() # flag=False 创建一个 event 对象
t1 = threading.Thread(target=worker, args=(readis_ready,), name='t1')
t1.start()
t2 = threading.Thread(target=worker, args=(readis_ready,), name='t2')
t2.start()
logging.debug('first of all, check redis server, make sure it is OK, and then trigger the redis ready event')
time.sleep(6) # simulate the check progress
readis_ready.set() # flag=Ture
if __name__=="__main__":
main()
进程 multprocessing 模块
multprocessing 模块与 threading 模块使用同一套 api,使用方法调用方法与 threading 模块一样
代码示例:
from multiprocessing import Process
import time
def f(name):
print("hello",name,time.ctime())
time.sleep(1)
if __name__=="__main__":
p_list=[]
for i in range(3):
p=Process(target=f,args=("alvin:%s"%i,))
p_list.append(p)
p.start()
协程的应用:
协程是单线程的,不能切换。因为协程对 IO 操作的判断由自己控制
import time
# 可以实现并发
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] ←← Consuming %s...'% n)
time.sleep(1)
r = '200 OK'
def produce(c):
next(c)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] →→ Producing %s...'% n)
cr = c.send(n)
print('[PRODUCER] Consumer return: %s'% cr)
c.close()
if __name__=='__main__':
c = consumer()
produce(c)
gevent 模块的使用:
from gevent import monkey
monkey.patch_all()
import gevent
from urllib import request
import time
def f(url):
print('GET: %s' % url)
resp = request.urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url))
start=time.time()
gevent.joinall([
gevent.spawn(f,'https://itk.org/'),
gevent.spawn(f,'https://www.github.com/'),
gevent.spawn(f,'https://zhihu.com/'),
])
#f('https://itk.org/')
#f('https://www.github.com/')
#f('https://zhihu.com/')
print(time.time()-start)
Python-- 进程与线程
来源: http://www.bubuko.com/infodetail-2280123.html