# Python 线程与协程

### 线程

``from threading import Thread   import time  def _sum(x, y):       print("Compute {} + {}...".format(x, y))     time.sleep(2.0)     return x+y def compute_sum(x, y):       result = _sum(x, y)     print("{} + {} = {}".format(x, y, result))  start = time.time()   threads = [       Thread(target=compute_sum, args=(0,0)),     Thread(target=compute_sum, args=(1,1)),     Thread(target=compute_sum, args=(2,2)), ] for t in threads:       t.start() for t in threads:       t.join() print("Total elapsed time {} s".format(time.time() - start))  # Do not use Thread start = time.time()   compute_sum(0,0)   compute_sum(1,1)   compute_sum(2,2)   print("Total elapsed time {} s".format(time.time() - start))   ``
``Compute 0 + 0... Compute 1 + 1... Compute 2 + 2... 0 + 0 = 0 1 + 1 = 2 2 + 2 = 4 Total elapsed time 2.002729892730713 s Compute 0 + 0... 0 + 0 = 0 Compute 1 + 1... 1 + 1 = 2 Compute 2 + 2... 2 + 2 = 4 Total elapsed time 6.004806041717529 s ``

``from threading import Thread   import time   class ComputeSum(Thread):       def __init__(self, x, y):         super().__init__()         self.x = x         self.y = y     def run(self):         result = self._sum(self.x, self.y)         print("{} + {} = {}".format(self.x, self.y, result))     def _sum(self, x, y):         print("Compute {} + {}...".format(x, y))         time.sleep(2.0)         return x+y  threads = [ComputeSum(0,0), ComputeSum(1,1), ComputeSum(2,2)]   start = time.time()   for t in threads:       t.start() for t in threads:       t.join() print("Total elapsed time {} s".format(time.time() - start))   ``
``Compute 0 + 0... Compute 1 + 1... Compute 2 + 2... 0 + 0 = 0 1 + 1 = 2 2 + 2 = 4 Total elapsed time 2.001662015914917 s ``

``from threading import Thread, Lock   import time   _base = 1   _lock = Lock()   class ComputeSum(Thread):       def __init__(self, x, y):         super().__init__()         self.x = x         self.y = y     def run(self):         result = self._sum(self.x, self.y)         print("{} + {} + base = {}".format(self.x, self.y, result))     def _sum(self, x, y):         print("Compute {} + {}...".format(x, y))         time.sleep(2.0)         global _base         with _lock:             result = x + y + _base             _base = result         return result threads = [ComputeSum(0,0), ComputeSum(1,1), ComputeSum(2,2)]  start = time.time()   for t in threads:       t.start() for t in threads:       t.join() print("Total elapsed time {} s".format(time.time() - start))   ``
``Compute 0 + 0... Compute 1 + 1... Compute 2 + 2... 0 + 0 + base = 1 1 + 1 + base = 3 2 + 2 + base = 7 Total elapsed time 2.0064051151275635 s ``

``_lock.acquire()   try:       result = x + y + _base     _base  = result finally:       _lock.release() ``

#### 死锁

``from threading import Lock   _base_lock = Lock()   _pos_lock  = Lock()   _base = 1  def _sum(x, y):       # Time 1     with _base_lock:         # Time 3         with _pos_lock:             result = x + y     return result def _minus(x, y):       # Time 0     with _pos_lock:         # Time 2         with _base_lock:             result = x - y     return result ``

### 协程

allowing multiple entry points for suspending and resuming execution at certain locations.

``def jump_range(upper):       index = 0     while index < upper:         jump = yield index         if jump is None:             jump = 1         index += jump jump = jump_range(5)   print(jump)   print(jump.send(None))   print(jump.send(3))   print(jump.send(None))   ``
``<generator object jump_range at 0x10e283518> 0 3 4 ``

``def wait_index(i):       # processing i...     return (yield i) def jump_range(upper):       index = 0     while index < upper:         jump = yield from wait_index(index)         if jump is None:             jump = 1         index += jump jump = jump_range(5)   print(jump)   print(jump.send(None))   print(jump.send(3))   print(jump.send(None))   ``
``<generator object jump_range at 0x10e22a780> 0 3 4 ``

`yield from` / `send` 似乎已经满足了协程所定义的需求，最初也确实是用 `@types.coroutine` 修饰器 将生成器转换成协程来使用，在 Python 3.5 之后则以专用的 `async/await` 取代了 `@types.coroutine/yield from`

``class Wait(object):       """     由于 Coroutine 协议规定 await 后只能跟 awaitable 对象，     而 awaitable 对象必须是实现了 __await__ 方法且返回迭代器     或者也是一个协程对象，     因此这里临时实现一个 awaitable 对象。     """     def __init__(self, index):         self.index = index     def __await__(self):         return (yield self.index) async def jump_range(upper):       index = 0     while index < upper:         jump = await Wait(index)         if jump is None:             jump = 1         index += jump jump = jump_range(5)   print(jump)   print(jump.send(None))   print(jump.send(3))   print(jump.send(None))   ``
``<coroutine object jump_range at 0x10e2837d8> 0 3 4 ``

#### 与线程相比

``import asyncio   import time   import types  @types.coroutine def _sum(x, y):       print("Compute {} + {}...".format(x, y))     yield time.sleep(2.0)     return x+y @types.coroutine def compute_sum(x, y):       result = yield from _sum(x, y)     print("{} + {} = {}".format(x, y, result)) loop = asyncio.get_event_loop()   loop.run_until_complete(compute_sum(0,0))   ``
``Compute 0 + 0... 0 + 0 = 0 ``

``import asyncio   import time  # 上面的例子为了从生成器过度，下面全部改用 async/await 语法 async def _sum(x, y):       print("Compute {} + {}...".format(x, y))     await asyncio.sleep(2.0)     return x+y async def compute_sum(x, y):       result = await _sum(x, y)     print("{} + {} = {}".format(x, y, result))  start = time.time()   loop = asyncio.get_event_loop()   tasks = [       asyncio.ensure_future(compute_sum(0, 0)),     asyncio.ensure_future(compute_sum(1, 1)),     asyncio.ensure_future(compute_sum(2, 2)), ] loop.run_until_complete(asyncio.wait(tasks))   loop.close()   print("Total elapsed time {}".format(time.time() - start))   ``
``Compute 0 + 0... Compute 1 + 1... Compute 2 + 2... 0 + 0 = 0 1 + 1 = 2 2 + 2 = 4 Total elapsed time 2.0042951107025146 ``