并发 并行 进程 线程 协程 异步I/O python async
一些草率不精确的观点:
并发: 一起发生,occurence: sth that happens。 并行: 同时处理. parallel lines: 平行线。thread.join()之前是啥?
落霞与孤鹜齐飞,秋水共长天一色。小霞与小鹜并发下单,线程1与线程2并行处理。并发是要被处理的,并行是处理并发的方法。要是不熟悉并行编程,它就成了要处理的"麻烦"。
一般地,每个线程有个函数,主线程有个main函数。无论线程在干啥,都可能被打断,其它线程得到执行的机会。线程调度器需要知道每个线程执行到哪里了,以便跳来跳去。与多个进程相比,多个线程共享全局变量或者说地址空间。Linux下fork创建进程,每个进程看起来也像函数,随后exec加载另一个可执行文件把它"冲掉"。没试过exec自己的a.out,应该可以。Windows下fork与exec合并成了CreateProcess,也许方便了,也许功能弱了。
与线程相比,协程长得也像函数,但不会被打断。sleep()说明不了协程的优越性,因为sleep并不是:
while (get_millisecond() <= time_out)
; // 占住CPU不干事
而是设个timer,通知调度器过段时间再执行自己。放弃控制权可能通过调用调度器里的函数来实现。异步I/O库里提供的read/recv/send/write等函数,都埋了放弃控制权的雷。
异步I/O是与阻塞式(blocking)I/O相对的,不是说异步I/O必用协程。协程倒是必用异步I/O。以读取HTTP Request为例,最简单的方式(Linux下)是:socket是fd (file descriptor), 从fd能拿到FILE*, fgets()就行。在没有从网上收到数据前,fgets()停在那里不动,我们不用在fgets()外包个for循环。很简单直接,但如何处理多路?异步I/O在event_loop()里留意多个socket上有无事件发生。若有则处理之,比如line += read_some_from_network(). 这是不舒服的,大多数人喜欢"我干这个我干那个"一路干到底,不喜欢"哎那谁这个你处理下"。
Client<->Proxy<->Server. Proxy特别适合用协程:逻辑清晰,I/O密集而不是CPU密集,切换丝滑而不顿挫。说不定fiber可以翻译成丝程。fibre并不比fiber格调高,前者英式拼写,后者AmE. colour... 先把美语说的有点样,再说端起来的事。
学python async的优先级不高。它的接口大改过,还会再大改吗?用python写个高性能的Web服务器? nginx...一堆。用python写个client,告诉小白用户得下载python,版本2和版本3也有要求?pyexe好像也不完美。基本上是同行在用,Ctrl-C退出大家相互理解的。
一个超超超简单的进程切换例子: https://www.cnblogs.com/funwithwords/p/15612922.html
下面的程序,一句time.sleep(30)就废了,还没上真正耗CPU的呢。当然epoll()也不能在处理event时占住CPU不放。也许我孤陋寡闻了,python有了新特性,比如:
some_statements_that_cost_10ms
__benice__
some_statements_that_cost_15ms
__benice__
from asyncio import * from threading import * import time _quit = 0 def set_quit(): print('Quitting...') global _quit _quit = 1 # We say that an object is an awaitable object if it can be used in an await expression. # Many asyncio APIs are designed to accept awaitables. async def task_fn(name): while not _quit: print(name) #time.sleep(30) await sleep(1) print(name, 'quits') async def task_master(name_prefix): tasks = [] for i in range(3): name = '%s.%c' % (name_prefix, chr(ord('A') + i)) tasks.append(create_task(task_fn(name))) await wait(tasks) class EvLoopThread(Thread): def run(self): loop = new_event_loop() loop.run_until_complete(task_master('Task')) del loop def create_evloop_thread(): th = EvLoopThread() th.start() return th #print(type(sleep), dir(sleep)) threads = [] for i in range(2): threads.append(create_evloop_thread()) try: input() except KeyboardInterrupt: print('^C is pressed') set_quit() for th in threads: th.join() print('Bye')