ROS交流群
ROS Group
产品服务
Product Service
开源代码库
Github
官网
Official website
技术交流
Technological exchanges
激光雷达
LIDAR
ROS教程
ROS Tourials
深度学习
Deep Learning
机器视觉
Computer Vision

线程和协程



  • 在写程序的时候为了提高执行效率经常会用到线程.把任务分配到不同的线程里面同时执行,这样即使其中一个被阻塞了,程序还是可以运行,程序运行效率得到了很大的提高.线程是一个经常用到的概念这里就不多说了.

    但是随着大家使用的线程越来越多,线程的劣势就越来越明显了.最有名的就是c10k问题.c10k问题是在写服务器程序时遇到的.如何使一个服务器同时和10K个客户端保持网络连接?一般的做法是给每个连接开一个独立的线程,但是这样就会有上万个线程.大量的资源被浪费在线程的管理上.线程已经无法再胜任这个任务了.

    在javascript中处理异步问题的方式给了我们很好的思路.javascript程序是单线程的,也就是某一时刻只能有一个程序在运行.但是javascript却可以很好的处理异步问题.下面以一个读取文件的例子来说明

    var fs = require('fs'); //引入文件处理库 fs
    fs.readFile('/etc/passwd', (err, data) => {
      if (err) throw err;
      console.log(data);
    });
    console.log("I'm not blocking");
    

    readFile函数的第一个参数是文件路径, 第二个参数是回调函数.当文件读取完成或者失败的时候回调函数会被执行.
    这样当程序运行到readFile的时候就不会被阻塞.也就是说在文件读取完成之前就会在终端中显示出I'm not blocking
    这是怎么实现的呢?
    这是因为javascript有一个叫做Event loop的线程,专门用来监控事件有没有触发,如果触发就调用相应的回调函数.比如说上面的readFile函数,实际上是相当于在Event Loop里面注册了一下.

    这就是协程的概念.用一个主线程去完成各种异步操作.看起来好像各自都有自己独立的线程一样.

    具体怎么实现一个协程呢?我们可以用python从头开始搭建出来.

    在python中有一种叫做generator的东西.比如 a = xrange(0,100000)这里a就是一个generator.一般使用时会觉得a是一个list.但是不是这样的.a中的元素只有在被使用到的时候才会被生成.

    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 异常
    

    这样a就可以用来表现协程的状态.在Event Loop之中不停的执行协程返回的generator直到这个generator返回StopIteration为止,再执行对应的回调函数.

    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
    
    

    个人感觉原理上就是如此了.

    实际上python中协程的用法

    为了方便使用,python把协程相关的东西做成了asyncio库.并且在python 3.5之中增加了await, async关键字(和C#学的)

    一个用协程的Hello World例子

    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")
    

    更详细的关于python的协程信息可以看这里

    不过个人感觉python的协程还是不是很自然.没有C#做的好.这个应该是python语言自身的限制造成的.


Log in to reply