您的位置:首页 > 编程语言 > Python开发

Python 多线程 多进程 协程 yield

2017-08-20 20:32 896 查看
python中多线程和多进程的最大区别是稳定性和效率问题

多进程互相之间不影响,一个崩溃了不影响其他进程,稳定性高

多线程因为都在同一进程里,一个线程崩溃了整个进程都完蛋

多进程对系统资源开销大,多线程对系统资源开销小,所以这方面来说多线程会比多进程快一点点

关于线程和进程的详细使用方法这里有https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319272686365ec7ceaeca33428c914edf8f70cca383000

等看完协程再补上

i/o密集型任务瓶颈都在网络,磁盘这些地方,适合用脚本语言进行多任务操作

3.协程

子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。

协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。



程最大的优势是高执行效率,因为子程序切换不是线程切换,而是由程序自己控制,没有切换线程的开销

不需要多线程锁

协程是建立在生成器基础上的,所以需要先理解迭代器生成器!!!

在一个线程里面不等待IO操作返回的结果,通过消息轮询来发送一个IO操作的请求后就执行其他的,等IO操作返回结果消息了再处理.这个不死等的方式不需要多线程多进程,在一个线程里实现,大大的提高了运行效率

对序列,字典,文件都可以使用iter()方法生成可迭代对象,然后用next()方法访问,这种东西咱们叫迭代器,一般用for循环读出内容

生成器是可迭代的

简单的生成器

my_generator = (x*x for x in range(4))


dir(my_generator ) 里面有iter()和next()属性,说明生成器是迭代器,可以用for循环读取内部的值

>>> for i in my_generator:
...     print i
...
0
1
4
9
>>> for i in my_generator:
...     print i
...


当第一遍循环的时候,将 my_generator 里面的值依次读出并打印,但是,当再读一次的时候,就发现没有任何结果。这种特性也正是迭代器所具有的,因为已经迭代到最后,指针指向没有内容了

生成器my_generator = (x*x for x in range(4))和列表解析式my_list = [x*x for x in range(4)]有啥不一样的地方呢,列表是先划分出内存来放列表中的数据的,生成器是用到的时候再申请内存,针对大量值的时候,列表占内存较多,迭代器(生成器是迭代器)的优势就在于少占内存,还有一点区别就是上面那个for循环读取内部的值,列表是可以反复取值的,不像生成器指针到最后没有了就不走了,列表的内存划分好了,每次想取值都可以

>>> for i in my_list:
...     print i
...
0
1
4
9
>>> for i in my_list:
...     print i
...
0
1
4
9


yield

python中有个词yield ,这家伙尼玛是生成器的标志

比如

def g():
yield 0
yield 1
yield 2

lalalal = g()
print type(lalalal)
print dir(lalalal)


#输出
<type 'generator'>
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']


iter和next,说明是迭代器,用lalalal.next()可以取值的

从上面的例子可以明白,含有yield关键字的函数返回值是一个生成器类型的对象,也是迭代器

我们任性的吧含有yield语句的函数叫做生成器,生成器是一种用普通函数语法定义的迭代器,反正记住,普通函数只要用了yield就变态成为生成器了,当然生成器具备迭代器属性

我们来看看在函数里 yield和return的具体区别

def r_return(n):
print "You taked me."
while n > 0:
print "before return"

return n
n -= 1
print "after return"
rr = r_return(3)
print rr

#输出
You taked me.
before return
3
#可以看出来,普通函数遇到return将值返回玩后,函数就不往下继续执行了

#再看用yield将函数变为generator生成器之后的样子
def r_return(n):
print "You taked me."
while n > 0:
print "before return"

yield n
n -= 1
print "after return"

rr = r_return(3)
print rr.next()
print rr.next()
print rr.next()

#输出
You taked me.
before return
3
after return
before return
2
after return
before return
1
#可以看出,用了yield比return好啊,返回完值(迭代一次),还可以再接着执行后面的内容(迭代第二次,第三次),直到跳出循环(没有可迭代的东西了)


一般的函数,都是止于 return。作为生成器的函数,由于有了 yield,则会遇到它挂起,如果还有 return,遇到它就直接抛出 SoptIteration 异常而中止迭代。

send

上面的生成器都是固定的,肚子里有啥就输出什么,自从python2.5之后,生成器有了一个新的特性,就是send方法,用它能直接往生成器的肚子里面传递数据了,让生成器不再是固定输出了

使用send可以接受一个外部传入的变量,然后根据变量内容计算结果之后返回,咱们之后要说的协程就是靠生成器函数的这个特性

<
c525
pre class="prettyprint">
def repeater():
n=None
while 1:
n = (yield n)

r= repeater()
r.send(None)
print r.send("new friend come in")
print r.send("tseeee")

#输出
new friend come in
tseeee


说下流程

这里和传统函数调用不一样,敲黑板,要通过r.send(None)(ps:如果用了send起手必须传None)或者r.next()或者next(r)来启动生成器函数,并进行到第一个yield语句结束的位置.此时,执行完了yield这一行语句,这个时候括号里的yield n返回初始值0,返回值n=0

然后send(“new friend come in”)这里会传入new friend come in,从下一行开始继续执行,并回到while头部,执行yield n这一行返回n=new friend come in了之后又停下来了,

.再执行r.send(“tseeee”),重复上一步,执行到yield n这一行返回n=tseeee之后再一次停下来
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: