<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[线程和协程]]></title><description><![CDATA[<p dir="auto">在写程序的时候为了提高执行效率经常会用到线程.把任务分配到不同的线程里面同时执行,这样即使其中一个被阻塞了,程序还是可以运行,程序运行效率得到了很大的提高.线程是一个经常用到的概念这里就不多说了.</p>
<p dir="auto">但是随着大家使用的线程越来越多,线程的劣势就越来越明显了.最有名的就是c10k问题.c10k问题是在写服务器程序时遇到的.如何使一个服务器同时和10K个客户端保持网络连接?一般的做法是给每个连接开一个独立的线程,但是这样就会有上万个线程.大量的资源被浪费在线程的管理上.线程已经无法再胜任这个任务了.</p>
<p dir="auto">在javascript中处理异步问题的方式给了我们很好的思路.javascript程序是单线程的,也就是某一时刻只能有一个程序在运行.但是javascript却可以很好的处理异步问题.下面以一个读取文件的例子来说明</p>
<pre><code>var fs = require('fs'); //引入文件处理库 fs
fs.readFile('/etc/passwd', (err, data) =&gt; {
  if (err) throw err;
  console.log(data);
});
console.log("I'm not blocking");
</code></pre>
<p dir="auto">readFile函数的第一个参数是文件路径, 第二个参数是回调函数.当文件读取完成或者失败的时候回调函数会被执行.<br />
这样当程序运行到readFile的时候就不会被阻塞.也就是说在文件读取完成之前就会在终端中显示出<code>I'm not blocking</code><br />
这是怎么实现的呢?<br />
这是因为javascript有一个叫做Event loop的线程,专门用来监控事件有没有触发,如果触发就调用相应的回调函数.比如说上面的readFile函数,实际上是相当于在Event Loop里面注册了一下.</p>
<p dir="auto">这就是协程的概念.用一个主线程去完成各种异步操作.看起来好像各自都有自己独立的线程一样.</p>
<p dir="auto">具体怎么实现一个协程呢?我们可以用python从头开始搭建出来.</p>
<p dir="auto">在python中有一种叫做generator的东西.比如 <code>a = xrange(0,100000)</code>这里a就是一个generator.一般使用时会觉得a是一个list.但是不是这样的.a中的元素只有在被使用到的时候才会被生成.</p>
<pre><code>def test():
    for i in range(0,10):
        yield i
a = test() # a就是一个generator
a.next() # 返回1
a.next() # 返回2
a.next() # 返回3
# 直到10
a.next() # 抛出 StopIteration 异常
</code></pre>
<p dir="auto">这样a就可以用来表现协程的状态.在Event Loop之中不停的执行协程返回的generator直到这个generator返回StopIteration为止,再执行对应的回调函数.</p>
<pre><code>class Defer:
    def __init__(self):
        self.waitFlag = True
        self.results = None

    def resolve(self, results):
        self.results = results
        self.waitFlag = False

    def get_status(self):
        while self.waitFlag:
            yield True

def code1():
    mDefer = Defer()
    # start a new thread, and do some time consuming works
    # when the work is complete
    mDefer.resolve(results)
    return mDefer

def code2():
    mDefer = Defer()
    # start a new thread, and do some time consuming works
    # when the work is complete
    mDefer.resolve(results)
    return mDefer

eventList = []
eventList.append(code1())
eventList.append(code2())
while True:
    for event in eventList:
        try:
            event.get_status()
        except:
            results = event.results

</code></pre>
<p dir="auto">个人感觉原理上就是如此了.</p>
<h3>实际上python中协程的用法</h3>
<p dir="auto">为了方便使用,python把协程相关的东西做成了asyncio库.并且在python 3.5之中增加了await, async关键字(和C#学的)</p>
<p dir="auto">一个用协程的Hello World例子</p>
<pre><code>import asyncio
eventloop = asyncio.new_event_loop()
asyncio.set_event_loop(eventloop)
async def helloWorld():
    await asyncio.sleep(10)
    print("Hello World")
eventloop.run_until_complete(helloWorld()) # 这一句是阻塞的,要等待目标任务完成才会执行下面的程序
print("I'm blocking")
</code></pre>
<p dir="auto">更详细的关于python的协程信息可以看<a href="https://docs.python.org/3/library/asyncio-task.html" target="_blank" rel="noopener noreferrer">这里</a></p>
<p dir="auto">不过个人感觉python的协程还是不是很自然.没有C#做的好.这个应该是python语言自身的限制造成的.</p>
]]></description><link>http://community.bwbot.org/topic/98/线程和协程</link><generator>RSS for Node</generator><lastBuildDate>Mon, 16 Mar 2026 05:34:29 GMT</lastBuildDate><atom:link href="http://community.bwbot.org/topic/98.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 19 Aug 2016 03:19:58 GMT</pubDate><ttl>60</ttl></channel></rss>