线程&进程
并发&并行
并发:是指系统具有处理多个任务(动作)的能力。
并行:是指系统具有 同时 处理多个任务(动作)的能力。
同步&异步
同步:当进程执行到一个IO(等待外部数据)的时候,-----等:同步
异步: -----不等:一直等到数据接受成功,再回来处理
问题: 多核没利用上?
GIL:全局解释锁
因为有GIL,所以,同一时刻,只有一个线程被CPU执行
任务:IO密集型 & 计算密集型
对于IO密集型的任务 :python的多线程的是有意义的
可以采用多进程+协程
对于计算密集型的任务:python的多线程就不推荐,python就不适用了
线程与进程的区别:
一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器) 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和
程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调
度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程
自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是
它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行
python的GIL
线程
import threading
import time def sayhi(num): #定义每个线程要运行的函数 print("running on number:%s" %num) time.sleep(3) if __name__ == '__main__': t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例 t1.start() #启动线程
t2.start() #启动另一个线程 print(t1.getName()) #获取线程名
print(t2.getName())
直接调用
import threading
import time class MyThread(threading.Thread):
def __init__(self,num):
threading.Thread.__init__(self)
self.num = num def run(self):#定义每个线程要运行的函数 print("running on number:%s" %self.num) time.sleep(3) if __name__ == '__main__': t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start() print("ending......")
继承调用
其他方法:
# run(): 线程被cpu调度后自动执行线程对象的run方法
# start():启动线程活动。
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。 threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
例:
import threading
from time import ctime,sleep
import time
def music(func):
print("Begin listening to %s. %s"%(func,ctime()))
sleep(4)
print("end listening %s"%ctime())
def move(func):
print("Begin watching at the %s!%s"%(func,ctime()))
sleep(5)
print("end watching %s"%ctime())
threads=[]#用来放线程的对象
t1=threading.Thread(target=music,args=("七里香",))
threads.append(t1)
t2=threading.Thread(target=move,args=("啊甘正传",))
threads.append(t2)
if __name__ == '__main__':
t1.setDaemon(True)#守护线程,主进程关闭则t1关闭。
t2.setDaemon(True)#主线程关闭时则关闭
for t in threads:#循环得到线程的实例
t.start()#开启线程
# print(threading.currentThread())#打印线程的对象
# print(threading.enumerate())#打印正在开启的线程列表
# print(threading.activeCount())#打印正在开启的线程个数
# print(t2.isAlive())#线程是否运行
# t2.setName(123)#跟改线程名
# print(t.getName())#查看线程名
# t1.join()#等待线程结束,在往下走
# t2.join()
print("all over %s"%ctime())
其他方法
同步锁(也叫互斥锁):
import time
import threading def sub():
global num
temp=num
time.sleep(0.00001)
num=temp-1
num=100 l=[] for i in range(100):
t=threading.Thread(target=sub)
t.start()
l.append(t) for i in l:i.join()
print(num)
资源会被破坏
lock=threading.Lock(),加上同步锁。
import time
import threading def sub():
global num
lock.acquire()
temp=num
time.sleep(0.00001)
num=temp-1
lock.release()
num=100 l=[]
lock=threading.Lock()
for i in range(100):
t=threading.Thread(target=sub)
t.start()
l.append(t) for i in l:i.join()
print(num)
数据部分成串行
死锁和递归锁:
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。下面是一个死锁的例子:
import threading
import time class MyThresd(threading.Thread):#类的继承方式启动线程
def actionA(self):
A.acquire() #获得A锁
print(self.name,"gotA",time.ctime())
time.sleep(2)
B.acquire() #获得B锁 print(self.name,"gotB",time.ctime())
time.sleep(1) B.release() #释放B锁
A.release() #释放A锁 def actionB(self):
B.acquire()
print(self.name,"gotA",time.ctime())
time.sleep(2)
A.acquire() print(self.name,"gotB",time.ctime())
time.sleep(1) A.release()
B.release() def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
A=threading.Lock() #产出A锁
B=threading.Lock() #产生B锁
# r_lock=threading.RLock() #递归锁,把A、B锁换成Rlock()
l=[]
for i in range(5):
t=MyThresd() #实例创建线程
t.start() #启动线程,执行run方法
l.append(t) #对象加到列表里
for i in l: #便利获取对象
i.join() #等待线程结束
print("ending.....")
死锁
为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
import threading
import time class MyThresd(threading.Thread):#类的继承方式启动线程
def actionA(self):
r_lock.acquire() #获得A锁
print(self.name,"gotA",time.ctime())
time.sleep(2)
r_lock.acquire() #获得B锁 print(self.name,"gotB",time.ctime())
time.sleep(1) r_lock.release() #释放B锁
r_lock.release() #释放A锁 def actionB(self):
r_lock.acquire()
print(self.name,"gotA",time.ctime())
time.sleep(2)
r_lock.acquire() print(self.name,"gotB",time.ctime())
time.sleep(1) r_lock.release()
r_lock.release() def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
# A=threading.Lock() #产出A锁
# B=threading.Lock() #产生B锁
r_lock=threading.RLock() #递归锁,把A、B锁换成Rlock()
l=[]
for i in range(5):
t=MyThresd() #实例创建线程
t.start() #启动线程,执行run方法
l.append(t) #对象加到列表里
for i in l: #便利获取对象
i.join() #等待线程结束
print("ending.....")
递归锁
解死锁:acquire有一个计数,获得一把锁就加一,只要计数器一直大于0,其他线程就要一直等待
同步条件(Event):
event = threading.Event()
event.wait() #等待event被设定
event.set() #设定event
event.clear() #清空event的设定
import threading,time
class Boss(threading.Thread):
def run(self):
print("Boss:今晚大家都要加班到22;00")
print(event.isSet()) #打印是否被设定默认是False
event.set() #设定标志位
time.sleep(4)
print("22:00到了,下班吧!")
event.set() class Worker(threading.Thread):
def run(self):
event.wait() #阻塞等待,等待标志位被设定,设定就往下走
print("太苦B了")
# event.clear() #清空标志位
time.sleep(2)
event.wait() #清空event后,再次阻塞
print("终于下班了")
if __name__ == '__main__':
event=threading.Event() #相当于是个标志位 threads=[]
for i in range(5):
threads.append(Worker()) #创建5个线程对象
threads.append(Boss()) #创建1个线程对象
for t in threads:
t.start() #所有线程全部执行
for t in threads:
t.join() #等待线程全部执行完
print("ending.....")
同步条件:event=threading.Event()
信号量(Semaphore):
import threading,time
class MyThread(threading.Thread):
def run(self):
if semaphore.acquire(): #一次可以进来5把锁
print(self.name)
time.sleep(2)
semaphore.release() if __name__ == '__main__':
semaphore=threading.Semaphore(5) #获取锁的对象,设置同时开启5个线程,默认是一个 threads=[]
for i in range(100):
threads.append(MyThread())
for t in threads:
t.start()
for t in threads:
t.join()
信号量(Semaphore):开启x个线程
*多线程利器---队列(queue)
列表是不安全的数据结构
import threading,time,queue
li=[1,2,5,3,4,5] print(li)
def pri():
while li :
a=li[-1]
print(a)
time.sleep(1)
# try:
li.remove(a)
# except Exception as e:
# print("-"*10,a,e) t1=threading.Thread(target=pri)
t1.start()
t2=threading.Thread(target=pri)
t2.start()
同一时刻两个线程取到了一个数字
queue列队类的方法:
创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10) #参数代表列队能放多少个值
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。 将一个值放入队列中
q.put(10) #block默认为True,改为False则抛出异常
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。 将一个值从队列中取出
q.get() #block默认为True,改为Flase则抛出异常
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,
get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。 Python Queue模块有三种队列及构造函数:
*1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
*2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
*3、还有一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize) 此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作
其他模式:
import queue #先进后出 q=queue.LifoQueue() q.put(34)
q.put(56)
q.put(12) #优先级
# q=queue.PriorityQueue()
# q.put([5,100])
# q.put([7,200])
# q.put([3,"hello"])
# q.put([4,{"name":"alex"}]) while 1: data=q.get()
print(data)
生产者消费者模型:
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这就像,在餐厅,厨师做好菜,不需要直接和客户交流,而是交给前台,而客户去饭菜也不需要不找厨师,直接去前台领取即可,这也是一个结耦的过程。
import time,random
import queue,threading q=queue.Queue() def Producer(name):
count=0
while count < 10:
print("making......")
time.sleep(2)
q.put(count)
print("Producer %s has produced %s baozi.."%(name,count))
count+=1
# q.task_done() #发信号,放了一个数据
q.join()
print("ok......") def Consumer(name):
count=0
while True:
time.sleep(4)
data = q.get() # 接收列队的数据
print("eating.....")
# q.join() #队列有数据了才往下走
q.task_done() print("\033[32;1mconsumer %s has eat %s baozi...\033[0m"%(name,data))
# else:
# print("----no baozi anymore-----")
count+=1 p1=threading.Thread(target=Producer,args=(" A ",))
c1=threading.Thread(target=Consumer,args=(" B ",))
c2=threading.Thread(target=Consumer,args=(" C ",))
c3=threading.Thread(target=Consumer,args=(" D ",))
p1.start()
c1.start()
c2.start()
c3.start()
进程
调用的方法:from multiprocessing import Process
进程的调用1:创建
from multiprocessing import Process
import time
def f(name):
time.sleep(1)
print('hello', name,time.ctime()) if __name__ == '__main__':
p_list=[]
for i in range(3):
p = Process(target=f, args=('alvin',))
p_list.append(p)
p.start()
for i in p_list:
i.join()
print('end')
进程的调用2:继承
from multiprocessing import Process
import time class MyProcess(Process):
def __init__(self):
super(MyProcess, self).__init__() #继承父类的__init__方法
#self.name = name def run(self):
time.sleep(1)
print ('hello', self.name,time.ctime()) if __name__ == '__main__':
p_list=[]
for i in range(3):
p = MyProcess() #拿到进程对象
p.daemon=True
p.start()
p_list.append(p) # for p in p_list:
# p.join() #等待子进程没执行完,主进程就要等待
print('end')
要显示单个进程ID,这里是一个扩展的例子:os.getppid(),os.getpid()
from multiprocessing import Process
import os
import time def info(title):
print("title:", title)
print('parent process:', os.getppid()) #程序运行的父进程的id号
print('process id:', os.getpid()) #程序运行的进程的id号 def f(name):
info('function f')
print('hello', name) if __name__ == '__main__':
info('main process line')
time.sleep(1)
print("------------------")
p = Process(target=info, args=('yuan',))
p.start()
p.join()
要显示单个进程ID,这里是一个扩展的例子:
线程&进程的更多相关文章
- python之线程进程协成
		
线程与进程 什么是线程 线程是进程一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源,但是它可与同属一个线程的 ...
 - 文成小盆友python-num11-(1)  线程 进程 协程
		
本节主要内容 线程补充 进程 协程 一.线程补充 1.两种使用方法 这里主要涉及两种使用方法,一种为直接使用,一种为定义自己的类然后继承使用如下: 直接使用如下: import threading d ...
 - python_21_线程+进程+协程
		
python_线程_进程_协程 什么是线程? -- os能够进行运算调度的最小单位,被包含在进程之中,是一串指令的集合 -- 每个线程都是独立的,可以访问同一进程下所有的资源 什么是进程? -- 每个 ...
 - 线程&进程&协程
		
线程 线程是应用程序中工作的最小单元,它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.Threading用 ...
 - python--再看并行之协程线程进程
		
1.gevent协程适合I/O密集,不适合CPU密集. 3.gevent协程无法发挥多核优势,事实上,协程只是以单线程的方式在运行. 3.子程序就是协程的一种特例 项目实际应用 from gevent ...
 - 15.python并发编程(线程--进程--协程)
		
一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...
 - Python 多线程、多进程 (三)之 线程进程对比、多进程
		
Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.多线程与多进 ...
 - python线程进程
		
多道技术: 多道程序设计技术 所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行.即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬.软件资源.当一道程序因I/O请 ...
 - python之并发编程(线程\进程\协程)
		
一.进程和线程 1.进程 假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是 ...
 
随机推荐
- NumPy 广播机制(Broadcasting)
			
一.何为广播机制 a.广播机制是Numpy(开源数值计算工具,用于处理大型矩阵)里一种向量化数组操作方法. b.Numpy的通用函数(Universal functions) 中要求输入的两个数组sh ...
 - MySQL数据库改名的三种方法
			
前不久去面试,被问到Innodb引擎的表如何改数据库名,当时我也只回答了MyISAM改如何操作,被一些细节问题打败,真是操蛋. 如果表示MyISAM那么可以直接去到数据库目录mv就可以. Innodb ...
 - 报错解决——linux下执行sh出现异常"syntax error: unexpected end of file"
			
有时我们在linux下执行一个sh文件,会报错“SYNTAX ERROR:UNEXPECTED END OF FILE”,这个现象主要是工作的系统环境改变造成的. 若最初脚本中是在windows下,使 ...
 - vue监听滚动事件 实现某元素吸顶或者固定位置显示
			
https://blog.csdn.net/wang1006008051/article/details/78003974 1.监听滚动事件 利用VUE写一个在控制台打印当前的scrollTop, 首 ...
 - [django]模板中自定义变量&django模板中的变量
			
django自定义模板变量 context_processors.py def mysetings(request): return { 'NAME': 'maotai' } settings.py ...
 - 使用shape设置android控件只有部分边框有颜色
			
<?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android=" ...
 - 如何写一个优秀的GitHub项目README文档?
			
今天给大家介绍一个Github上的README文档写作教程模版,该模版目前获得6634颗星星,2296Fork,相对而言,还是比较得到大家认可的.不花哨,不别出心裁,一个比较实用的,普适性的架子:所谓 ...
 - VS中去掉空格虚点
			
Ctrl + R+W 可以在VS中添加或移除 空格虚点.
 - 如何打印一棵树(Java)
			
1.有一棵多叉树,将它打印出来. import java.util.LinkedList; /** * 需求:按层打印一棵树 * 说明:树是保存在一个链表中 * created by wangjunf ...
 - Redis:Sentinel哨兵
			
简介 Sentinel的作用就是主从切换:Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,R ...