简述python进程,线程和进程线程协程的异同区别及应用场景

  一直以来写博客都是实用主义者,只写用法,没信心写原理,但是每一次写作业的过程都有一种掘地三尺的感觉,终于,写博客困难症重症患者经历了漫长的思想斗争,还是决定把从网上淘到的各种杂货和自己的总结放在一起,写一次原理文。。。算是继上次装饰器之后的第二次挖祖坟事件,只是这次是主动挖~~~
开胃菜&&同步和异步
  记得刚毕业那会儿,同事问我,知不知道同步和异步,我一脸茫然的摇摇头,换来的是一脸看白痴的表情,现在渐渐明白了一些,觉得并没有多高深。举个栗子:你叫我去吃饭,我听到了就立刻和你去吃饭,如果我没听到,你就一直叫我,直到我听见和你一起去吃饭,这个过程叫同步;异步过程指你叫我去吃饭,然后你就去吃饭了,而不管我是否和你一起去吃饭。而我得到消息后可能立即就走,也可能过段时间再走。
  所以喽,我们不要被那些看起来晦涩的专业名词吓到了,不过就是吃顿饭的事儿,同事又是一脸看白痴的表情&_&:吃货学python就只能想到吃。。。
  哈哈,官方的解释搬过来:
    同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
    异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。
初始化进程、线程与协成的概念
什么是进程?
  进程,是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。前面的话我也没懂,用非官方的白话来解释就是&&执行中的程序是进程,比如qq不是进程,但是当我们双击qq开始使用它的时候,它就变成了一个进程。我们写的python程序,只有当我们执行它的时候,它才是进程。我们正在执行的IE浏览器,QQ,pycharm都是进程,从操作系统的角度来讲,每一个进程都有它自己的内存空间,进程之间的内存是独立的。
什么是线程?
  线程,有时被称为轻量级进程,是程序执行流的最小单元。我们可以理解为,线程是属于进程的,我们平时写的简单程序,是单线程的,多线程和单线程的区别在于多线程可以同时处理多个任务,这时候我们可以理解为多线程和多进程是一样的,我可以在我的进程中开启一个线程放音乐,也可以开启另外的线程聊qq,但是进程之间的内存独立,而属于同一个进程多个线程之间的内存是共享的,多个线程可以直接对它们所在进程的内存数据进行读写并在线程间进行交换。
进程与线程之间的关系
先推荐一个链接,这篇文章用漫画的形式讲解了进程与线程的关系:
  如上图,假装我们已经看完了上面的连接。这里来为偷懒的同志们解释一下,左图为进程与线程之间的关系。每个进程都有属于自己的线程,至少一个。右图是进程、单线程进程,多线程进程在内存中的情况。
关于python线程的那个传说:
  在python界一直有着一个古老的传说,那就是python的多线程是鸡肋,那么这个传说的信度到底有多少呢?如果我们的代码是CPU密集型(涉及到大量的计算),多个线程的代码很有可能是线性执行的,所以这种情况下多线程是鸡肋,效率可能还不如单线程,因为有context switch(其实就是线程之间的切换和线程的创建等等都是需要消耗时间的);但是:如果是IO密集型,多线程可以明显提高效率。例如制作爬虫,绝大多数时间爬虫是在等待socket返回数据。这个时候C代码里是有release GIL的,最终结果是某个线程等待IO的时候其他线程可以继续执行。
  那么,为什么我们大python会这么不智能呢?我们都知道,python是一种解释性语言,在python执行的过程中,需要解释器一边解释一边执行,我们之前也介绍了,同一个进程的线程之间内存共享,那么就会出现内存资源的安全问题,python为了线程安全,就设置了全局解释器锁机制,既一个进程中同时只能有一个线程访问cpu。作为解释型语言,python能引入多线程的概念就已经非常不易了,目前看到的资料php和perl等多线程机制都是不健全的。解释型语言做多线程的艰难程度可以想见。。。具体下面的链接推荐:python的最难问题。
&  正是由于python多线程的缺陷,我们在这里需要引入协成的概念。
什么是协程?
  协程是一种用户态的轻量级线程。如果说多进程对于多CPU,多线程对应多核CPU,那么事件驱动和协程则是在充分挖掘不断提高性能的单核CPU的潜力。我们既可以利用异步优势,又可以避免反复系统调用,还有进程切换造成的开销,这就是协程。协程也是单线程,但是它能让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来。它是实现推拉互动的所谓非抢占式协作的关键。对于python来说,由于python多线程中全局解释器导致的同时只能有一个线程访问cpu,所以对协程需求就相比于其他语言更为紧迫。
进程、线程与协程
  从硬件发展来看,从最初的单核单CPU,到单核多CPU,多核多CPU,似乎已经到了极限了,但是单核CPU性能却还在不断提升。server端也在不断的发展变化。如果将程序分为IO密集型应用和CPU密集型应用,二者的server的发展如下:
    IO密集型应用: 多进程-&多线程-&事件驱动-&协程    CPU密集型应用:多进程--&多线程&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  调度和切换的时间:进程&& &&& 线程&& &&&协程
偷懒的同学看这里&_&:不需要实现复杂的内存共享且需利用多cpu,用多进程;实现复杂的内存共享及IO密集型应用:多线程或协程;实现复杂的内存共享及CPU密集型应用:协程
  开始写连载的博客了,哈哈,感觉还是短短的文章可读性强~~~
  进程、线程和协成的详解如下:
    进程篇:
    线程篇&&基础篇:
    线程篇&&进阶篇:
    线程篇&&线程池:
    协程篇:
  参考文献:    同步和异步相关:
    python的最难问题【译】多线程相关:
    浅谈对协程的理解:
阅读(...) 评论()简述Python中的进程、线程、协程
作者:编程青年的崛起
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Python中的进程、线程、协程的相关资料,需要的朋友可以参考下
进程、线程和协程之间的关系和区别也困扰我一阵子了,最近有一些心得,写一下。
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
进程和其他两个的区别还是很明显的。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
Python线程
定义:Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time
def show(arg):
time.sleep(1)
print 'thread'+str(arg)
for i in range(10):
t = threading.Thread(target=show, args=(i,))
print 'main thread stop
上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
更多方法:
•start 线程准备就绪,等待CPU调度
•setName 为线程设置名称
•getName 获取线程名称
•setDaemon 设置为后台线程或前台线程(默认)
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
•join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
•run 线程被cpu调度后自动执行线程对象的run方法
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。所以,可能出现如下问题:
import threading
import time
gl_num = 0
def show(arg):
global gl_num
time.sleep(1)
gl_num +=1
print gl_num
for i in range(10):
t = threading.Thread(target=show, args=(i,))
print 'main thread stop'
import threading
import time
gl_num = 0
lock = threading.RLock()
def Func():
lock.acquire()
global gl_num
gl_num +=1
time.sleep(1)
print gl_num
lock.release()
for i in range(10):
t = threading.Thread(target=Func)
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
•clear:将“Flag”设置为False
•set:将“Flag”设置为True
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
def do(event):
print 'start'
event.wait()
print 'execute'
event_obj = threading.Event()
for i in range(10):
t = threading.Thread(target=do, args=(event_obj,))
event_obj.clear()
inp = raw_input('input:')
if inp == 'true':
event_obj.set()
Python 进程
from multiprocessing import Process
import threading
import time
def foo(i):
print 'say hi',i
for i in range(10):
p = Process(target=foo,args=(i,))
注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。
进程数据共享
进程各自持有一份数据,默认无法共享数据
#!/usr/bin/env python
#coding:utf-8
from multiprocessing import Process
from multiprocessing import Manager
import time
def foo(i):
li.append(i)
print 'say hi',li
for i in range(10):
p = Process(target=foo,args=(i,))
print ('ending',li)
#方法一,Array
from multiprocessing import Process,Array
temp = Array('i', [11,22,33,44])
def Foo(i):
temp[i] = 100+i
for item in temp:
print i,'-----&',item
for i in range(2):
p = Process(target=Foo,args=(i,))
#方法二:manage.dict()共享数据
from multiprocessing import Process,Manager
manage = Manager()
dic = manage.dict()
def Foo(i):
dic[i] = 100+i
print dic.values()
for i in range(2):
p = Process(target=Foo,args=(i,))
'c': ctypes.c_char, 'u': ctypes.c_wchar,
'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
'h': ctypes.c_short, 'H': ctypes.c_ushort,
'i': ctypes.c_int, 'I': ctypes.c_uint,
'l': ctypes.c_long, 'L': ctypes.c_ulong,
'f': ctypes.c_float, 'd': ctypes.c_double
当创建进程时(非使用时),共享数据会被拿到子进程中,当进程中执行完毕后,再赋值给原值。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process, Array, RLock
def Foo(lock,temp,i):
将第0个数加100
lock.acquire()
temp[0] = 100+i
for item in temp:
print i,'-----&',item
lock.release()
lock = RLock()
temp = Array('i', [11, 22, 33, 44])
for i in range(20):
p = Process(target=Foo,args=(lock,temp,i,))
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
•apply
•apply_async
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process,Pool
import time
def Foo(i):
time.sleep(2)
return i+100
def Bar(arg):
pool = Pool(5)
#print pool.apply(Foo,(1,))
#print pool.apply_async(func =Foo, args=(1,)).get()
for i in range(10):
pool.apply_async(func=Foo, args=(i,),callback=Bar)
print 'end'
pool.close()
pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭
线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from greenlet import greenlet
def test1():
gr2.switch()
gr2.switch()
def test2():
gr1.switch()
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
import gevent
def foo():
print('Running in foo')
gevent.sleep(0)
print('Explicit context switch to foo again')
def bar():
print('Explicit context to bar')
gevent.sleep(0)
print('Implicit context switch back to bar')
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
遇到IO操作自动切换:
monkey.patch_all()
import gevent
import urllib2
def f(url):
print('GET: %s' % url)
resp = urllib2.urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, '/'),
gevent.spawn(f, '/'),
以上所述是小编给大家介绍的Python中的进程、线程、协程的相关知识,希望对大家有所帮助!
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具用户名:Linus_hai
文章数:131
访问量:58299
注册日期:
阅读量:1297
阅读量:3317
阅读量:460224
阅读量:1144664
51CTO推荐博文
进程:进程之间不共享任何状态,进程的调度由操作系统完成,每个进程都有自己独立的内存空间,进程间通讯主要是通过信号传递的方式来实现的,实现方式有多种,信号量、管道、事件等,任何一种方式的通讯效率都需要过内核,导致通讯效率比较低。由于是独立的内存空间,上下文切换的时候需要保存先调用栈的信息、cpu各寄存器的信息、虚拟内存、以及打开的相关句柄等信息,所以导致上下文进程间切换开销很大,通讯麻烦。&线程:线程之间共享变量,解决了通讯麻烦的问题,但是对于变量的访问需要锁,线程的调度主要也是有操作系统完成,一个进程可以拥有多个线程,但是其中每个线程会共享父进程像操作系统申请资源,这个包括虚拟内存、文件等,由于是共享资源,所以创建线程所需要的系统资源占用比进程小很多,相应的可创建的线程数量也变得相对多很多。线程时间的通讯除了可以使用进程之间通讯的方式以外还可以通过共享内存的方式进行通信,所以这个速度比通过内核要快很多。另外在调度方面也是由于内存是共享的,所以上下文切换的时候需要保存的东西就像对少一些,这样一来上下文的切换也变得高效。协程:协程的调度完全由用户控制,一个线程可以有多个协程,用户创建了几个线程,然后每个线程都是循环按照指定的任务清单顺序完成不同的任务,当任务被堵塞的时候执行下一个任务,当恢复的时候再回来执行这个任务,任务之间的切换只需要保存每个任务的上下文内容,就像直接操作栈一样的,这样就完全没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快;另外协程还需要保证是非堵塞的且没有相互依赖,协程基本上不能同步通讯,多采用一步的消息通讯,效率比较高。本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)Python_进程、线程及协程
时间: 12:10:17
&&&& 阅读:71
&&&& 评论:
&&&& 收藏:0
标签:一、Python进程
  IO密集型----多线程
  计算密集型----多进程
  1、单进程  
from multiprocessing import Process
def foo(i):
print(‘你好哈‘,i)
if __name__ == ‘__main__‘:
#if __name__ == ‘__main__‘:只可做测试调用,不能用于生产,windows不支持,linux中可不用添加if __name__ == ‘__main__‘
for i in range(10):
t = Process(target=foo,args=(i,))
  注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。
  进程数据共享
  由于进程在内存中具有独立的地址空间,且每个地址空间各持有一份数据,默认情况下无法共享数据  
#方法一:进程共享数据:Array
from multiprocessing import Process
from multiprocessing import Array
def foo(i,arg):
arg[i] = i +100 #每一个进程加100
for item in arg:
print(item)
#输出迭代数据
print("----------")
if __name__ == "__main__":
li = Array(‘i‘,10) #创建数组,i 等于数据格式为整型,并设置10个元素给数据
for i in range(10):
#设置10个进程
p = Process(target=foo,args=(i,li,))#创建进程
p.start() #执行进程
#方法二:常用进程共享
from multiprocessing import
from multiprocessing import Manager
def foo(i,arg):
arg[i] = i +100
print(arg.values())
if __name__ == "__main__":
obj = Manager()
li = obj.dict()
for i in range(10):
p = Process(target=foo,args=(i,li,))
# time.sleep(0.01)
#方式二:join进程之间串联进行
‘c‘: ctypes.c_char,
‘u‘: ctypes.c_wchar,
‘b‘: ctypes.c_byte,
‘B‘: ctypes.c_ubyte,
‘h‘: ctypes.c_short, ‘H‘: ctypes.c_ushort,
‘i‘: ctypes.c_int,
‘I‘: ctypes.c_uint,
‘l‘: ctypes.c_long,
‘L‘: ctypes.c_ulong,
‘f‘: ctypes.c_float, ‘d‘: ctypes.c_double
类型对应表
#创建进程池from multiprocessing import Process,Queue
def f(i,q):
print(i,q.get())
#回去队列中元素
if __name__ == "__main__":
q.put(123)
#将数据put进队列
q.put(456)
q.put(789)
for i in range(10):
#共设置10个进程池
p = Process(target=f,args=(i,q,)) #创建进程
p.start() #执行进程
&  进程池
  进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
  进程池常用方法:  
apply &:串行执行每一个进程,即只有当一个进程执行完之后,第二个进程才会开始执行
apply_async &:并行执行所有进程,同时执行所有进程
multiprocessing import Pool
import time
def f1(arg):
time.sleep(1)
print(arg)
if __name__ == "__main__":
pool = Pool(5)
#创建进程池
for i in range(10):
#创建10个进程
pool.apply(func=f1,args=(i,)) #apply:让进程去进程池中获取数据,只有等待一个执行完一个元素后,第二个进程接着执行
# pool.apply_async(func=f1,args=(i,))
print("end")
#当0个进程执行完之后,输出end
apply_async &:并行执行所有进程,同时执行所有进程
terminate()#程序执行此时,立即终止所有进程,不管进程池中是否含有任务
multiprocessing import Pool
import time
def f1(arg):
time.sleep(1)
print(arg)
if __name__ == "__main__":
pool = Pool(5)
#创建进程池,每一次可同时执行5个进程
for i in range(10):
#创建10个进程
#pool.apply(func=f1,args=(i,)) #apply:让进程去进程池中获取数据,只有等待一个执行完一个元素后,第二个进程接着执行
pool.apply_async(func=f1,args=(i,)) #apply_async:方法:并行运行所有进程
# print("end")
#当0个进程执行完之后,输出end
pool.close()#所有任务(即)执行完毕
time.sleep(2)
pool.terminate()#当程序运行此时,立即终止所有进程,不管进程池中任务是否执行完
# pool.join()
  进程中常用方法由:Lock,Rloack,Event,Condition,Smaphore等于线程中方法一样
  1、进程锁:  
from multiprocessing import RLock,Lock,Event,Condition,Semaphore
from multiprocessing import Process
from multiprocessing import queues
from multiprocessing import Array
import multiprocessing
import time
def foo(i,list,lc):
lc.acquire() #给进程上锁
list[0]=list[0]-1
#每一次进程调用子进程时减一
time.sleep(1)
print("say hi",list[0])
#输出每一次进程调用
lc.release()
#给进程解锁
if __name__ == "__main__":
li = Array(‘i‘,1)
#python引用数组,i:表示整型数据,1:带包进程数组中含有一个元素
li[0]=10 #设置数组长度为10 lock = RLock() #创建进程锁 for i in range(10): #创建10个进程 p = Process(target=foo,args=(i,li,lock)) #创建进程 p.start() #执行进程
  2、多进程
二、Python线程
  定义:线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必  不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
  threading模块:提供线程相关操作,线程是应用程序中工作的最小单位
  1、单线程
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
#创建一个class类
def show(arg):
#arg:传参
time.sleep(2)
print(‘thread‘+str(arg))
#将传参转换至字符串形式
for i in range(10):
#创建10个线程
t = threading.Thread(target=show,args=(i,))
#线程就绪,等到CPU调度,
# print(‘main thread stop‘)
& 上述代码创建了10个&前台&线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令
更多方法:
线程准备就绪,等待CPU调度
为线程设置名称
获取线程名称
&setDaemon
设置为后台线程或前台线程(默认)
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
线程被cpu调度后自动执行线程对象的run方法  
#自定义线程
import time
class MyThread(threading.Thread):
#继承父类threading.Thread
def __init__(self, num): #MyThread类__ini__方法
threading.Thread.__init__(self)
self.num = num
def run(self):
#定义每个线程执行的函数,此时:self == 调用对象(t1或者t2对象)
print(‘running on number:%s‘ % self.num)
time.sleep(3)
#每一个线程睡眠3秒
if __name__ == "__main__":
t1 = MyThread(1)
#创建t1对象,并将参数1复制给t1对象
t2 = MyThread(2)
#创建t2对象,并将参数1复制给t2对象
t1.start()
t2.start()
# running on number:1
# running on number:2
自定义线程 
import threading
def f1(arg):
print(arg)
for i in range(10): #设置10个线程
t = threading.Thread(target=f1,args=(i,)) #创建线程
#输出:0-9数据
自定义线程二
  生产者和消费者
import queue,time
import threading
q = queue.Queue(20)
def productor(arg):
:param arg:
q.put(str(arg)+"-买票")
for i in range(30):
t = threading.Thread(target=productor,args=(i,))
#创建买票线程生产者,并将动态参数i传递给productor(arg)
#执行买票线程
# if i == 30:
def consumer(arg):
服务器后台,
:param arg:
while True:
print(arg,q.get())
#获取队列中存在元素
time.sleep(1)
sk = threading.BoundedSemaphore(5)
for j in range(5):
t = threading.Thread(target=consumer,args=(j,))#创建买票线程生产者,并将动态参数j传递给consumer(arg)
#执行c线程
生产者和消费者模式
    队列
  Python中常用队列方法:
  put放数据,是否阻塞,阻塞时的超时事件
  get取数据(默认阻塞),是否阻塞,阻塞时的超时事件
  qsize():获取队列中有多少个元素
  maxsize:最大支持的个数
  1、先进先出
  &queue.Queue(2)方法:创建先进先出队列,参数2表示队列中最多可含有两个元素,否则超过队列中设置的最大队列则报队列满(queue.Full)错误, 
import queue
import time
# put放数据,是否阻塞,阻塞时的超时事件
# get取数据(默认阻塞),是否阻塞,阻塞时的超时事件
# qsize():获取队列中有多少个元素
# maxsize 最大支持的个数
q = queue.Queue(2)
#创建队列,带参数,则表示队列最大可放多少个数据
print(q.qsize())
#获取队列中有多少个数据
# q.put(15,timeout=2)
#当队列中设置长度为2时,此时在往队列中增加元素时,超过2秒,报错queue.Full
q.put(15,block=False,timeout=2)
print(q.qsize())
#获取队列中有多少个数据
print("------------")
print(q.get())
#获取队列中元素
print(q.get(block=False))
#get取数据(默认阻塞),当block=False表示不堵塞
print(q.get(timeout=2))
#设置获取队列中元素超时时间2秒,超过则直接执行下面代码
print(q.get(block=False,timeout=2))
  2、后进先出
  queue.LifoQueue()方法:创建后进先出队列
import queue
# 队列后进先出
q= queue.LifoQueue()
q.put(123)
#将数据put队列中
q.put(234)
print(q.get()) #获取队列中的元素
#输出:234
  3、队列优先级
  queue.PriorityQueue()方法:创建队列优先级队列
#队列优先级,按照下标进行优先级别排序
q = queue.PriorityQueue()
#创建队列优先级别q值
q.put((1,"lcj"))
#将数据put队列中
q.put((0,"alex"))
q.put((4,"xiaoluo"))
print(q.get())
#获取队列中的元素
#输出(0, ‘alex‘)
  4、双向队列
  queue.deque()方法:创建双向队列
import queue
q = queue.deque() #创建双向队列
q.append(33)
#将元素33加入队列中
q.append(44)
q.append(55)
q.appendleft(99)
print(q.pop())
#pop:在队列中提取一个元素
print(q.popleft())
  线程锁(Lock,RLock)
  一个进程下有多个线程,且线程是共享进程资源,每一个线程肯能执行N条语句后,当多个线程同时修改一天数据时可能会出现脏数据,所以,出现线程锁,同一时间只允许一个线程操作
  Lock,RLock区别?
  Lock是阻塞其他线程对共享资源的访问,且同一线程只能acquire一次,如多于一次就出现了死锁,程序无法继续执行。为了保证线程对共享资源的独占,又避免死锁的出现,就有了RLock。RLock允许在同一线程中被多次acquire,线程对共享资源的释放需要把所有锁都release。即n次acquire,需要n次release
  线程在未加锁情况下,主线程回一次性执行所有的线程且会产生多个线程同用一个数据,产生脏数据  
import threading
import time
#定义一个全局变量
def show(arg):
global num
#对全局变量num进行重新赋值
time.sleep(1)
print(num)
for i in range(10):
#定义十个线程
t = threading.Thread(target=show,args=(i,))#
# 执行线程
线程未加锁
线程加锁特定:每一个线程执行一条数据,防止多个线程重用一条数据产生脏数据
import threading
import time
#定义一个全局变量
lock = threading.RLock()
#定义一个线程锁
def show(arg):
lock.acquire()
global num
#对全局变量num进行重新赋值
time.sleep(1)
#每一个线程执行时睡眠一秒钟
print(num)
lock.release()
for i in range(10):
#定义十个线程
t = threading.Thread(target=show,args=(i,))#创建主线程
# 执行线程
&  信号量(Semaphore)
  互拆锁:同时只允许一个线程更改数据,而Semapphore是同时允许一定数量的线程更改数据,比如:一个萝卜一个坑,只有空余的坑才能进入占座
  BoundedSemaphore(5)方法:表示5个线程同时运行
import threading,time
def run(n):
k1.acquire()
time.sleep(1)
print("run the threading:%s" %n)
k1.release() #解锁
if __name__ == ‘__main__‘:
k1 = threading.BoundedSemaphore(5) #设置线程最多同时运行5个线程
for i in range(30):
#设置线程数为30
t = threading.Thread(target=run,args=(i,))
t.start() #执行线程
  事件(event)
  python线程的事件用于主线程控制其他子线程的执行,事件主要提供是三个方法:set、wait、clear
  事件处理的机制:全局定义了一个&Flag&,如果&Flag&值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果&Flag&值为True,那么event.wait 方法时便不再阻塞。  
clear:将&Flag&设置为False
set:将&Flag&设置为True&
wait:检测主线程状态
import threading,time#代码从上往下执行,由t.start调用子线程执行lcj方法,第一次输出i值,#当线程执行值wait时,判断线程状态,红灯(clear):停,绿灯(set):行#主线程继续运行至inp,当用户输如true时,主线程执行set方法,将线程转态设置绿灯,继续运行,则子线程继续执行i+100
def lcj(i,event):
time.sleep(1)
event.wait()
#检测是什么等,如果是红灯,则停,绿灯:则行
print(i+100)
event_obj = threading.Event()
#创建一个线程事件
for i in range(10):
#设置30个线程
t = threading.Thread(target=lcj,args=(i,event_obj,))
event_obj.clear()
#设置成红灯
inp = input("&&:").strip()
if inp ==‘true‘:
#如果用户输入:true,系统则经过wait检查之后执行其下面打印语句
event_obj.set() #设置成绿灯
&  条件(Contion)
  当线程处于等待时,只有满足某条件时,才释放N个线程继续执行子线程下代码
  1、条件wait方法用法
import threading
def run(i,con):
con.acquire()
con.wait()
#检测主线程状态,当主线程客户端输入3,则子线程输出队列中前三个元素每一个各加100输出
print(i+100)
con.release()
# if __name__ == "__main__":
con = threading.Condition()
for i in range(10):
t = threading.Thread(target=run,args=(i,con,))
#创建主线程
t.start() #执行子线程
while True:
inp = input("&&&:").strip()
if inp == ‘q‘:
# 此三个必须放在一起、acquire、notify、release
con.acquire()
con.notify(int(inp))
#notify()方法不会释放所占用的锁,输入几就释放几个元素,比如:客户输入2,则子线程输出100,101
con.release()
  2、条件wait_for方法:  
def contion():
ret = False
i = input("&&&&:")
if i =="true":
ret = True
ret = False
return ret
def run(i,con):
#输出所有线程
con.acquire()#加锁
con.wait_for(contion)
#wait_for:等待条件=true成立,则执行contion函数中语句
print(i+100)
#当主线程条件成立,则执行i+100
con.release() #解锁
c = threading.Condition()
#创建线程条件
for i in range(10): #设置10个线程
t = threading.Thread(target=run,args=(i,c,)) #创建线程
t.start() #执行线程
  定时器(time)
  python中定时器:指定N秒之后执行子线程操作  
from threading import Timer
def lcj():
print("hello,world")
t = Timer(1,lcj)
#定时器:1秒后执行lcj函数,并输出hello,world
t.start() #执行线程
  2、多线程&
三、线程池
  线程池原理:可理解为是一个容器(容器中可指定大小),在容器中取一个线程则少一个线程,再无没有线程时等待,线程执行完毕,将线程归还给线程池
  1、基本线程池&
#自定义线程池
import queue
import threading
import time
class ThreadPool:
def __init__(self,maxsize=5):
#创建构造方法,设置最大线程为5个线程
self.maxsize = maxsize
self._q = queue.Queue(maxsize)#_q:下划线 为了区别,创建队列
for i in range(maxsize):
#每次循环最大线程
self._q.put(threading.Thread) #将类名put队列中
def get_thread(self):
return self._q.get()
def add_thread(self):
self._q.put(threading.Thread)#队列含有:threading.Thread
pool = ThreadPool(5)
#线程池最大个数为5,即每次最多只能获取5个线程
def task(arg,p):
print(arg)
time.sleep(1)
p.add_thread()#从线程池取完一次数据之后 再次想线程池中获取数据,直到执行完100个线程
for i in range(100):
#循环100次
#t==threading.Thread类
t = pool.get_thread()
obj = t(target=task,args=(i,pool,))
#创建主线程
obj.start()
#执行子线程池
&  2、高级线程池&
四、Python协程
  协程原理:利用一个线程,分解一个线程成为多个&微线程&
  线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。
  协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
  协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;
  协程常用方法:
  greenlet:底层  
from greenlet import greenlet
lcj2.switch()
lcj2.switch()
lcj1.switch()
lcj1 = greenlet(f1)
lcj2 = greenlet(f2)
lcj1.switch()
#第一步:lcj1.switch():执行f1函数并输出12
#第二步:在函数f1中lcj2.switch(),则执行f2函数并输出56
#第三步:在f2函数执行lcj1.switch(),则执行f1函数,并输出34
#第四步:在f1函数执行lcj2.switch(),则执行f2函数,并输出78
#最后输出顺序为:12,56,34,78
  gevent:高级
import gevent
def foo():
print("running in foo")
gevent.sleep(1)
print(‘Explicit context switch to foo agein‘)
def bar():
print(‘explicit context to bar‘)
gevent.sleep(1)
print(‘implicit context switch back to bar‘)
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
# running in foo
# explicit context to bar
# Explicit context switch to foo agein
# implicit context switch back to bar
  遇到IO操作自动切换:  
from gevent importmonkey.patch_all()
#monkey.patch_all()
修改原来socket,
对IO请求进行封装
import gevent
import requests
def f(url):
print(‘GET: %s‘% url)
#获取所有URL
resp = requests.get(url)
data = resp.text
#获取URL内容
print("%d bytes received from %s." % (len(data),url))
gevent.joinall([
gevent.spawn(f, "https://www.python.org/"),
gevent.spawn(f, "/"),
gevent.spawn(f, "/"),
&&国之画&&&& &&&&chrome插件
版权所有 京ICP备号-2
迷上了代码!

我要回帖

更多关于 进程 线程 协程异同 的文章

 

随机推荐