日月神话

或者:异步/等待不是您所想的。 (Or: async/await is not what you think it is.)

Make no mistake: we are living through a new asynchronous programming renaissance. The programming community has spent the 2010s rediscovering the techniques that we used to use to handle highly-concurrent workloads when we didn’t have the memory available to spawn an operating system thread to handle every single connection. This trend is incredibly apparent when we look at the languages and language features that are heavily discussed and debated. Consider the meteoric rise of Node.JS (the ultimate async-first language), or the incredible prominence of the goroutine and green threading primitives in Go, or the incredible number of languages that are hopping on the async/await train that C♯ got started.

没错:我们正在经历新的异步编程复兴。 当我们没有足够的内存来产生操作系统线程来处理每个连接时,编程社区在2010年代就重新发现了用于处理高并发工作负载的技术。 当我们查看经过大量讨论和辩论的语言和语言功能时,这种趋势非常明显。 考虑一下Node.JS(最终的异步优先语言)的迅猛发展,或者Go语言中goroutine和绿色线程原语的惊人表现,或者C♯获得的async / await训练中跳跃的语言数量之多。开始了 。

While there are many interesting things to talk about in that prior list of languages and features, I really want to focus on the last one: async/await. In particular, I want to talk about a fairly popular blog post that takes aim at the async/await syntactic feature: What Color is Your Function?. For those who are new to the topic, I’ll very briefly explain what async/await are. However, I will not summarise the prior blog post: it’s a good piece of work and should be read in its entirety. If you’re totally unfamiliar with this discussion, read my little async/await summary, then read the blog post, then come back here. I promise the blog post won’t go away while you’re gone.

在先前的语言和功能列表中有很多有趣的事情要谈论 ,我真的很想关注最后一个: async / await 。 特别是,我想谈谈一个颇受欢迎的博客文章,该文章针对async / await语法功能: 您的功能是什么颜色? 。 对于那些刚接触该主题的人,我将非常简要地解释什么是async / await 。 但是,我不会总结以前的博客文章:这是一项很好的工作,应完整阅读。 如果您完全不熟悉此讨论,请阅读我的async / await摘要,然后阅读博客文章,然后返回此处。 我保证您离开后该博客文章不会消失。

One last note: I am explicitly discussing only concurrent programming here, not parallel programming. If you’re not comfortable with this distinction, go watch Rob Pike explain the difference and come back. Fundamentally, this discussion is related to parallelism but not really affected by it in any profound way.

最后一点:我在这里只讨论并发编程,不讨论并行编程。 如果您对这种区别不满意,请观看Rob Pike解释区别并返回。 从根本上讲,此讨论与并行性有关,但并未真正受到任何深远的影响。

异步/等待入门 (An Async/Await Primer)

What is async/await at a high level?

什么是async /高层await

Basically, they’re tools for explicitly marking concurrent control flow using language keywords. If you have an operation that is going to need to wait for some I/O or for some background process to complete, you can wrap that in a function (call it “function A”) and mark that function as async. Then, you can call that function from some other function (“function B”) using the keyword await, which is a signal to the language runtime that it should pause execution of function B until function A’s I/O has completed.

基本上,它们是使用语言关键字显式标记并发控制流的工具。 如果您有需要等待一些I / O或某些后台进程完成的操作,则可以将其包装在一个函数中(称为“函数A”)并将该函数标记为async 。 然后,您可以使用关键字await从其他功能(“功能B”)中调用该功能,这是向语言运行时发出的信号,它应暂停功能B的执行,直到功能A的I / O完成为止。

Put another way, async/await are keywords that signal to the language that your code is willing to pause its execution at this point to let other code run. It’s cooperative multitasking!

换句话说, async / await是关键字,用于向语言表示您的代码愿意在此时暂停执行以让其他代码运行。 这是协作式多任务处理 !

Under the hood of different languages async/await do different things, but the net effect is always that they allow you to write concurrent code in a somewhat linear manner. In effectively-single-threaded languages like Python, they let you turn a series of callbacks written as individual functions into a series of what appear to be mostly ordinary functions but magically can yield their flow of control to someone else. This is a neat trick, and it’s extremely helpful from the perspective of clearing up some of the downsides of traditional concurrent code: specifically, callback hell.

在不同语言的背景下, async / await做不同的事情,但是最终的结果是,它们总是允许您以某种线性方式编写并发代码。 在像Python这样的有效单线程语言中,它们使您可以将作为单个函数编写的一系列回调转换为一系列似乎大部分为普通函数的回调,但可以神奇地将它们的控制流传递给其他人。 这是一个巧妙的窍门,从清除传统并发代码的一些缺点(特别是回调地狱)的角度来看,这非常有用。

That’s all the time I’m willing to spend on this primer here. If you want more detail on how they work in Python (and I recommend you get it, this is a cool idea well worth understanding), Brett Cannon has a great blog post that covers this.

我一直都愿意在这里花这本入门书。 如果您想更详细地了解它们在Python中的工作方式(我建议您理解它,这是一个很值得理解的好主意), Brett Cannon的博客文章很不错 。

已经到点 (Get To The Point Already)

So, lets talk about function colour. Bob Nystrom’s great blog post about function colour that I linked above uses the idea of coloured functions to talk about the fact that the async/await syntactic feature effectively means that a programming language has two types (or “colours”) of function. One type is what you’d think of as your standard function: for the rest of this post I’ll call that a “synchronous” function. The other type is a function that is annotated as async: what we’ll call (inventively) “asynchronous” functions.

因此,让我们谈谈功能颜色。 我上面链接的鲍勃·尼斯特罗姆(Bob Nystrom)在有关函数颜色的精彩博客文章中使用了函数颜色的概念来谈论async / await句法功能实际上意味着编程语言具有两种类型(或“颜色”)函数的事实。 一种类型是您认为是标准函数的类型:在本文的其余部分中,我将其称为“同步”函数。 另一种类型是被标注为async的函数:我们将(创造性地)称为“异步”函数。

Bob points out that there are rules for these kinds of function. Specifically, while synchronous functions can be called from any kind of function, asynchronous functions must be called only from other asynchronous functions by means of the await keyword. Put in Python-specific terms, consider the following functions:

鲍勃指出这类功能有规定。 具体来说,尽管可以从任何一种函数中调用同步函数,但必须仅通过await关键字从其他异步函数中调用异步函数。 用特定于Python的术语,请考虑以下功能:

def function_a(some_socket_or_something):return some_socket_or_something.recv(8192)async def function_b(some_streamreader_or_something):return (await some_streamreader_or_something.read(8192))

def function_a(some_socket_or_something):return some_socket_or_something.recv(8192)async def function_b(some_streamreader_or_something):return (await some_streamreader_or_something.read(8192))

If you want to call function_a, you can call that from anywhere, even inside function_b. However, you cannot call function_b from within function_a. In Python, if you try to do this, you’ll find that function_b never actually executes: it returns immediately and does nothing. In more statically-typed languages like C♯, you’ll get a compiler error instead. Python’s behaviour here (subtly failing to execute your code) is actually one of the most common bugs hit by people using Python async functions: forgetting to annotate them with await.

如果要调用function_a ,则可以在任何地方(甚至在function_b内部) function_b 。 但是,你不能叫function_b从内部function_a 。 在Python中,如果尝试执行此操作,则会发现function_b从未真正执行过:它会立即返回并且不执行任何操作。 在像C♯这样的更多静态类型的语言中,您会收到编译器错误。 实际上,Python的行为(可能无法执行代码)实际上是人们使用Python异步函数遇到的最常见的错误之一:忘记使用await对其进行注释。

From Bob’s perspective, this dichotomy makes your life sufficiently hard that it is more-or-less unbearable (specifically, Bob will “start grinding [his] teeth” when he hears about this kind of thing). That’s fair enough: people like what they like, and there is nothing wrong with saying that you’d rather approach this a different way. People should write code in whatever way makes them most productive, and if that means you’d like to use thousands of threads and write in Visual Basic 6 then hell, you go Glen Coco. Godspeed.

从鲍勃的角度来看,这种二分法使您的生活变得十分艰难,以至于变得或多或少难以忍受(特别是,鲍勃在听到这种事情时会“开始磨牙”)。 这很公平:人们喜欢他们喜欢的东西,并且说您宁愿以不同的方式来对待也没有错。 人们应该以任何使他们效率最高的方式编写代码,如果这意味着您想使用数千个线程并用Visual Basic 6编写,那么该死的是Glen Coco。 上帝的速度。

However, recently we have seen discussions in the Python community around the pervasiveness of async/await that have rather misunderstood why async/await is worth having. In particular, from time to time you’ll catch someone saying that all non-threaded concurrent code (that is, all code that uses some variant of the Reactor pattern) is necessarily coloured code, and that async/await exist to simply make those colours obvious.

但是,最近我们在Python社区中看到了关于async / await的普遍性的讨论,这些讨论已经误解了为什么async / await值得拥有的原因。 特别是,您有时会发现有人说所有非线程并发代码(即,使用Reactor模式的某些变体的所有代码)都必须是彩色代码,并且存在async / await只是为了使那些颜色明显。

I think that fundamentally this idea, which is parallel to Bob’s, is a severe misunderstanding of the way async code works. In the rest of this post I’d like to outline what I mean.

我认为从根本上讲,与鲍勃(Bob)相似的想法是对异步代码工作方式的严重误解。 在本文的其余部分中,我想概述一下我的意思。

颜色不是强制性的 (Colour Isn’t Mandatory)

So let’s get something out of the way right now: function colour is a tool for writing async code, not a requirement of it.

因此,让我们立即摆脱困境:函数颜色是用于编写异步代码的工具,而不是必需的工具。

This is extremely obviously true. For example, in a prior job I worked on a gigantic C codebase that was written entirely in a cooperative multitasking style. That is, it was very similar to Node.JS, but written entirely in C. Now, C does not have any method of describing function colour, nor does it have any mechanism of giving a function a colour. In C, your code executes synchronously, step by step, forever. However, we were perfectly capable of writing a real, serious application, entirely in C, that didn’t use a callstack-based resumption model like the one Bob discusses. So it’s clear that function colour isn’t intrinsic to this problem.

这显然是事实。 例如,在之前的工作中,我研究了完全以协作式多任务处理风格编写的巨大C代码库。 也就是说,它与Node.JS非常相似,但是完全用C编写。现在,C没有任何描述函数颜色的方法,也没有给函数赋颜色的任何机制。 在C语言中,您的代码永远永远同步执行。 但是,我们完全有能力完全用C编写一个真正的,认真的应用程序,而没有使用Bob所讨论的基于调用堆栈的恢复模型。 因此很明显,功能颜色不是此问题固有的。

Moreover, it’s not even intrinsic to Python. I know that Twisted is (cruelly and undeservedly) un-loved in the wider Python community, but consider a very basic Twisted program.

而且,它甚至不是Python固有的。 我知道Twisted在更广泛的Python社区中是(残酷和不当之选)不受欢迎的,但是考虑一个非常基本的Twisted程序。

This is a basic Twisted Protocol, which is responsible for managing a network connection. This is a core demonstration of how to write concurrent code: all of these functions are intended to be callbacks.

这是基本的Twisted协议 ,它负责管理网络连接。 这是如何编写并发代码的核心演示:所有这些功能均旨在作为回调。

My question is: where is the function colour here? None of these functions are async functions, so that’s not it. Are they implicitly coloured? Well, if they were that could only be because they’d be unable to be called from synchronous code. But that’s not true at all. For example, you can use this Protocol entirely from synchronous code:

我的问题是:这里的功能颜色在哪里? 这些功能都不是async功能,不是吗。 它们是暗色的吗? 好吧,如果是那样的话,那只能是因为无法从同步代码中调用它们 。 但这根本不是真的。 例如,您可以完全通过同步代码使用此Protocol

import socketdef main():p = PrinterProtocol()s = socket.create_connection(('http2bin.org', 80))s = s.makefile()p.connectionMade(s)while True:data = s.read(8192)if data:p.dataReceived(data)else:p.connectionLost(None)breaks.close()

import socketdef main():p = PrinterProtocol()s = socket.create_connection(('http2bin.org', 80))s = s.makefile()p.connectionMade(s)while True:data = s.read(8192)if data:p.dataReceived(data)else:p.connectionLost(None)breaks.close()

There’s no async here at all! Look at all these blocking socket calls. We spend so much time waiting for the kernel to do stuff it’s crazy. All of these functions are synchronous functions in the grand tradition of synchronous functions. There is no requirement for function colour at all here.

这里根本没有异步! 查看所有这些阻塞的套接字调用。 我们花了很多时间等待内核做疯狂的事情。 在同步功能的传统中,所有这些功能都是同步功能。 此处完全不需要功能颜色。

What about Futures (or, as Twisted calls them, Deferreds)? Bob says this in his post:

期货(或如Twisted所说的Deferreds )又如何呢? 鲍勃在他的帖子中这样说:

You still can’t call a function that returns a future from synchronous code. (Well, you can, but if you do, the person who later maintains your code will invent a time machine, travel back in time to the moment that you did this and stab you in the face with a #2 pencil.)

您仍然无法调用从同步代码返回未来的函数。 (好吧,可以,但是如果这样做,后来维护代码的人会发明一台时光机,回到过去的那一刻,并用#2铅笔刺在脸上。)

Well, that statement is true-ish. It’s certainly true of asyncio.Future, because asyncio.Future is a Python awaitable, and also requires a running event loop to execute any code. However, it’s not true of Twisted’s Deferred. Twisted’s Deferred, unlike asyncio’s Future, is not an event loop construct: it does not require an event loop to execute. When you call callback on a Deferred, Twisted will immediately execute any attached callbacks synchronously, in-line with the function that just fired the Deferred. This means that Deferreds are also not coloured objects, and you can do things like refactor the code above to this:

好吧,那句话是真实的。 asyncio.Future当然是正确的,因为asyncio.Future是一个可asyncio.Future的Python,并且还需要一个运行中的事件循环来执行任何代码。 但是,Twisted的Deferred并非如此。 与asyncio的Future不同,Twisted的Deferred不是事件循环构造:它不需要事件循环来执行 。 当您在Deferred上调用callback时,Twisted将立即同步执行任何附加的回调,并与刚刚触发Deferred的函数保持一致。 这意味着Deferred也不是有色对象,您可以执行以下操作来重构上面的代码:

This code also runs perfectly happily using the skeleton code I outlined above. Still no function colours here: everything is just a synchronous function call.

使用我上面概述的框架代码,该代码也可以完美地运行。 这里仍然没有函数颜色:一切都只是一个同步函数调用。

Hopefully, this will convince you that there is nothing mandatory about function colours when it comes to writing asynchronous code. You don’t have to use them. You can always construct your world out of a collection of synchronous functions that expect to run as callbacks. The only moment that function colour shows up is the moment you start making blocking I/O calls, and that there is where this discussion gets interesting.

希望这可以使您确信,在编写异步代码时,函数颜色没有强制要求。 您不必使用它们。 您始终可以根据希望作为回调运行的同步函数集合来构建自己的世界。 功能颜色显示的唯一时刻是您开始进行阻塞I / O调用的时刻,并且在此讨论中变得很有趣。

为什么我们使用功能颜色 (Why We Use Function Colour)

So hopefully I’ve just made it clear to you that you can write asynchronous code using entirely synchronous function calls: there is no requirement for coloured functions. So why does function colour come up at all?

因此,希望我已经向您阐明,您可以使用完全同步的函数调用来编写异步代码:不需要彩色函数。 那么,为什么功能色会出现呢?

A hint at the answer can be found in Glyph’s 2014 blog post Unyielding. This blog post is nominally about green threading vs regular threading, but along the way it touches on the four modes of concurrent programming:

有关答案的提示可以在Glyph的2014年博客文章Unyielding中找到 。 这篇博客文章名义上是关于绿色线程与常规线程的,但在此过程中,它涉及了并发编程的四种模式:

  1. Straight callbacks: Twisted’s IProtocol, JavaScript’s on<foo> idiom, where you give a callback to something which will call it later and then return control to something (usually a main loop) which will execute those callbacks,
  2. “Managed” callbacks, or Futures: Twisted’s Deferred, JavaScript’s Promises/A[+], E’s Promises, where you create a dedicated result-that-will-be-available-in-the-future object and return it for the caller to add callbacks to,
  3. Explicit coroutines: Twisted’s @inlineCallbacks, Tulip’s yield from coroutines, C#’s async/await, where you have a syntactic feature that explicitly suspends the current routine,
  4. and finally, implicit coroutines: Java’s “green threads”, Twisted’s Corotwine, eventlet, gevent, where any function may switch the entire stack of the current thread of control by calling a function which suspends it.
  1. 直接回调:Twisted的IProtocol ,JavaScript的on<foo>习惯用法,您在其中提供回调,以便稍后进行调用,然后将控制权返回到将执行这些回调的某个事物(通常是主循环),
  2. “托管”回调或Futures:Twisted的Deferred ,JavaScript的Promises/A[+] , E的Promises ,您可以在其中创建一个专用的结果,该结果将在将来可用,并将其返回给调用方添加回调,
  3. 明确的协程:Twisted的@inlineCallbacks ,Tulip的协程yield from ,C#的async/await ,其中您具有显式挂起当前例程的语法功能,
  4. 最后是隐式的协程: Java的“绿色线程” ,Twisted的Corotwine , eventlet , gevent ,其中任何函数都可以通过调用挂起它的函数来切换当前控制线程的整个堆栈。

If we reframe option 4 to just say “threads”, green or otherwise, then we can write our own list:

如果我们将选项4重新组织为只说“线程”(绿色或其他),那么我们可以编写自己的列表:

  1. Straight callbacks: uncoloured.
  2. Managed callbacks: usually uncoloured, but they may be coloured in some cases.
  3. Explicit coroutines: usually coloured, but they may be uncoloured in some cases (e.g. Twisted’s @inlineCallbacks, which returns an uncoloured Deferred).
  4. Threads: uncoloured.
  1. 直接回调:无色。
  2. 托管回调:通常不带颜色,但在某些情况下可以带颜色。
  3. 显式协程:通常是彩色的,但是在某些情况下它们可能是未着色的(例如Twisted的@inlineCallbacks ,它返回未@inlineCallbacksDeferred )。
  4. 线程:无色。

Given that colour is clearly not mandatory for any of these, why does Bob talk so vehemently about colour?

考虑到颜色显然不是其中任何一种强制性的,为什么鲍勃如此激烈地谈论颜色?

Well, fundamentally, Bob’s argument can be reframed. He gives himself away at the end of the post, when he asks “What language isn’t colored?” and then says this:

好吧,从根本上说,鲍勃的论点可以改写。 当他问“什么颜色没有上色?”时,他在帖子的末尾放弃了自己。 然后说:

Any guess what [uncoloured langauges] have in common?

你猜[无色语言]有什么共同点吗?

Threads. Or, more precisely: multiple independent callstacks that can be switched between. It isn’t strictly necessary for them to be operating system threads. Goroutines in Go, coroutines in Lua, and fibers in Ruby are perfectly adequate.

线程。 或者,更准确地说:可以在多个独立的调用堆栈之间进行切换。 严格来说,它们不必是操作系统线程。 Go中的Goroutines,Lua中的协程和Ruby中的纤维就足够了。

So, here we get to the rub. Bob’s rant about function colour is actually a rant about proactor vs reactor programming. His argument is that it is better to write code that blocks on I/O than code that expects its I/O to be done for it elsewhere in the code. It is better to write functions that do I/O and then have their call stack switched out than it is to write functions that expect to return all the way up their call stack for the I/O to occur.

所以,在这里,我们来摸索。 鲍勃对功能颜色的抱怨实际上是对前摄者与React堆编程的抱怨。 他的观点是,编写在I / O上阻塞的代码比期望在代码的其他地方对其进行I / O的代码更好。 最好编写执行I / O的功能,然后关闭其调用堆栈,而不是编写期望一直返回其调用堆栈以使I / O发生的函数。

There are two problems with that argument.

该论点有两个问题。

One of them is that the argument is poorly framed. You can see that Bob allows “multiple independent callstacks that can be switched between”, which is exactly what async/await allows! The only difference is that function colours are involved. So what Bob actually wants is for multiple independent callstacks and no coloured functions. That’s fine.

其中之一是论点的框架不完善。 您会看到Bob允许“可以在多个独立的调用堆栈之间进行切换”,这正是async / await允许的! 唯一的区别是涉及功能颜色。 因此Bob真正想要的是多个独立的调用堆栈,并且没有彩色函数。 没关系。

The second problem is that options 1 through 3 in my above list exist in part because of the drawbacks of threaded programming. If we allow green threading with small stack sizes as an option (à la goroutines), then the reason we avoid threading in the first place is because we are concerned about shared-state pre-emptive multitasking. As Glyph says in Unyielding:

第二个问题是上面列出的选项1至3部分存在是由于线程编程的缺点。 如果我们允许使用栈大小小的绿色线程作为选择(请参阅goroutines),那么我们之所以避免使用线程,是因为我们担心共享状态的抢先式多任务处理。 正如Glyph在《不屈》中所说:

When you’re looking at a routine that manipulates some state, in a single-tasking, nonconcurrent system, you only have to imagine the state at the beginning of the routine, and the state at the end of the routine. To imagine the different states, you need only to read the routine and imagine executing its instructions in order from top to bottom. This means that the number of instructions you must consider is n, where n is the number of instructions in the routine. By contrast, in a system with arbitrary concurrent execution – one where multiple threads might concurrently execute this routine with the same state – you have to read the method in every possible order, making the complexity nn.

在单任务非并发系统中,当您查看操纵某些状态的例程时,您只需要想象该例程开始时的状态,以及例程结束时的状态。 要想像不同的状态,您只需要阅读例程并想象按照从上到下的顺序执行其指令即可。 这意味着您必须考虑的指令数为n,其中n是例程中的指令数。 相反,在具有任意并发执行的系统中(一个多个线程可能以相同状态并发执行该例程的系统),您必须以每种可能的顺序读取该方法,从而使复杂度为n n

Put another way, threads are hard. Before you get your pitchforks out, note that I said hard, not impossible. If you find working with shared-state pre-emptive multitasking easy, or that it maps well onto your thought processes, more power to you. I am not here to tell you to stop using threads. I am here to tell you why we have function colours.

换句话说,线程很难。 在把干草叉拿出来之前,请注意我说的很努力,并非没有可能。 如果您发现使用共享状态的抢先式多任务处理很容易,或者它可以很好地映射到您的思维过程中,那么您将获得更多的功能。 我并不是要告诉您停止使用线程。 我在这里告诉您为什么我们要使用功能颜色。

So, if threads are hard (for some programmers), what are our other options? Well, the other option is cooperative multitasking. That is, only one bit of my code runs at once, and then it stops running to let other bits run. Options 1 through 3 of my above list give us that power. And, as I’ve demonstrated at length through this post, function colour is not necessary to achieve this kind of cooperative multitasking.

因此,如果线程很困难(对于某些程序员而言),那么我们还有其他选择吗? 好吧,另一个选择是协作多任务。 也就是说,我的代码只有一次运行一次,然后停止运行以让其他代码运行。 我上面列出的选项1到3给了我们这种力量。 而且,正如我在这篇文章中详细说明的那样,实现这种协作式多任务处理并不需要颜色功能。

What it is, though, is convenient! That’s really it. Despite Bob’s many arguments about how annoying async/await is, at least in Python it reinstates to the world of cooperative multitasking the one thing he says he wants: multiple independent callstacks that can be switched between. It does so at the cost of providing coloured functions. These are inconvenient, but in return for paying the cost of that inconvenience they allow programmers to avoid being stuck in callback hell or requiring them to reason through the complex ways a callback chain can fire or propagate errors. This makes it easier for programmers to reason about control flow and error propagation and exception flow and all the other nice things that we want to think about.

不过,这很方便! 就是这样 尽管鲍勃(Bob)对async / await是多么烦人有很多争论,但至少在Python中,它恢复了协作多任务的世界,这是他说的一件事:可以在多个独立的调用堆栈之间进行切换。 这样做是以提供彩色功能为代价的。 这些操作很不方便,但作为回报,您为此付出了不便的代价,这使程序员可以避免陷入回调地狱或要求他们通过回调链可以触发或传播错误的复杂方式进行推理。 这使程序员更容易推理控制流,错误传播,异常流以及我们要考虑的所有其他美好事物。

This is why we have coloured functions: because they make lives easier for many programmers. They are an optional language tool you can use to write codebases that are easier for some programmers to reason about. For me, I am happy to work with uncoloured callbacks: I have done it my entire programming career, and I’m finally at the point where I’m really pretty good at it. But, at least anecdotally, I can tell you that many (maybe even most) programmers are not comfortable doing it: they would like the clarity that async/await brings.

这就是我们使用彩色函数的原因:因为它们使许多程序员的工作变得更轻松。 它们是一种可选的语言工具,可用于编写一些程序员更容易理解的代码库。 对于我来说,我很高兴使用无颜色的回调:我在整个编程生涯中都完成了这项工作,最后我真的很擅长这一点。 但是,至少可以说,我可以告诉您,许多(也许甚至是大多数)程序员都不愿意这样做:他们希望async / await带来的清晰度。

However, given that we’re going to provide this convenience for our users, we should discuss briefly how to avoid the pitfalls of coloured functions. Because Bob is right: if you start colouring all your functions willy-nilly, you do start making things trickier.

但是,考虑到我们将为用户提供这种便利,我们应该简短地讨论如何避免使用彩色函数的陷阱。 因为鲍勃是对的:如果您开始随意着色所有功能,则确实会使事情变得棘手。

如何与彩色功能一起生活 (How To Live With Coloured Functions)

Don’t colour them.

不要给它们上色。

I’m serious: every time you write async in your code you have made a small admission of defeat. You couldn’t come up with a clear way to construct your code that didn’t involve you needing to do some form of I/O in the middle of it. That’s fine: as programmers our job is to balance the tradeoffs between expediency (using async whenever necessary) and good code structure (writing as little code as possible that requires I/O), and I’m sure as hell not going to judge you for choosing to put async everywhere.

我是认真的:每次您在代码中编写async代码时,都会承认失败。 您无法想出一种清晰的方法来构造您的代码,而无需在其中进行某种形式的I / O。 很好:作为程序员,我们的工作是在权宜之计(必要时使用async )和良好的代码结构(编写尽可能少的需要I / O的代码)之间权衡取舍,而且我敢肯定,这不会判断您选择将async传递到任何地方。

But you don’t need to do it. With care, there is no reason for more than about 10% of your codebase to be async functions. Almost all the rest of your code can just transform in-memory data representations from one form to another. You don’t have to do this, and certainly if you don’t care about code reusability or the various costs of writing async functions you should just go ahead and do that. But with care, and precision, most of your code doesn’t need it.

但是您不需要这样做。 小心一点,没有理由让代码库的大约10%以上成为async函数。 几乎所有其他代码都可以将内存中的数据表示形式从一种形式转换为另一种形式。 您不必这样做,当然,如果您不关心代码的可重用性或编写async函数的各种成本,则应该继续这样做。 但是经过精心和精确的处理,您的大多数代码都不需要它。

So when we have discussions about extending the async paradigm to another Python language feature (currently, generators), we shouldn’t get bogged down in whether we’re creating two parallel worlds of functions. Whether we do that is a choice of the community. If the community is careful, we can write tools and implementations that enable async-using programs without requiring them. We can write as much code as possible in a synchronous style. We can potentially replace the core of most of our libraries with code written like this, allowing only the tiniest amount of wrapper code to transform from synchronous to asynchronous code.

因此,当我们讨论将async范式扩展到另一个Python语言功能(当前是generators )时,我们不应该为是否要创建两个并行的函数世界而感到困惑。 我们是否这样做是社区的选择。 如果社区谨慎,我们可以编写无需程序即可启用async使用程序的工具和实现。 我们可以以同步方式编写尽可能多的代码 。 我们可以用这样编写的代码潜在地替换大多数库的核心,从而仅允许最少量的包装器代码从同步代码转换为异步代码。

All of this is possible. The community just needs to get comfortable with the idea that async is a tool for improving code clarity, rather than a requirement for writing asynchronous code. And I know I’ve spoken at length about Twisted here, but I think it’s important to remember that Twisted has learnt these lessons and learnt them well. Perhaps more importantly, though, it taught those lessons to asyncio. Every time you think you’ll use asyncio’s Streams API, stop and consider whether you can use Protocols instead. Because streams are coloured, but Protocols aren’t, and using Protocols will force you into a style where you avoid colouring your functions unnecessarily. This gives you the opportunity to write a codebase that is protected from the difficulties of coloured functions, where your code is testable without an event loop, where it can be run in a synchronous mode if you require it, and where it provides the opportunity for substantial code reuse.

所有这些都是可能的。 社区只需要对async是提高代码清晰度的工具而不是编写异步代码的要求的想法感到满意。 而且我知道我在这里详细谈到了Twisted,但我认为重要的是要记住Twisted已经学习了这些课程并且学得很好。 不过,也许更重要的是,它向异步学习了这些课程。 每当您认为自己将使用asyncio的Streams API时 ,请停止并考虑是否可以使用Protocols代替 。 因为流是彩色的,但协议不是彩色的,使用协议会迫使您进入一种避免不必要地给函数上色的样式。 这为您提供了编写代码库的机会,该代码库不受有色函数的困扰,可以在没有事件循环的情况下对代码进行测试,可以在需要时以同步模式运行代码,并且可以为大量的代码重用。

2Σ↑ (2 Σ ↑)

Code colour is a convenience, not a requirement. And we shouldn’t get too worked up about it, or worry that we’re segmenting our code. Instead, we should focus on using code colour sparingly, because while it adds clarity it also hurts reusability. Making that trade off well is one of the skills of being a programmer, and we should inform our community about that trade off, and then trust them to make the right call.

代码颜色是一种便利,不是必需的。 而且我们不应该对此太费劲,或者担心我们正在分割代码。 相反,我们应该专注于少量使用代码颜色,因为虽然它增加了清晰度,但同时也损害了可重用性。 做出良好的权衡是成为程序员的技能之一,我们应该将这种权衡告知我们的社区,然后相信他们做出正确的选择。

翻译自: https://www.pybloggers.com/2016/07/the-function-colour-myth/

日月神话

日月神话_功能色彩神话相关推荐

  1. Linux DMA Engine framework(2)_功能介绍及解接口分析

    转载.蜗窝科技,www.wowotech.net. Linux DMA Engine framework(2)_功能介绍及解接口分析 作者:wowo 发布于:2017-5-2 22:47 分类:Lin ...

  2. 05_SQL注入_功能语句报错注入盲注

    05_SQL注入_功能语句&报错回显&盲注 1. SQL 语句和网站功能 1.1 Web开发中常见语句 [本章代码来源于pikachu和sqli-lab中的靶场] 开发中,根据不同的需 ...

  3. FEC生鲜配送软件8大功能简述_功能列表

    筷云信息专为生鲜配送行业的企业提供独立部署的生鲜配送解决方案,筷云信息的生鲜配送系统覆盖企业上游的从采购到入库,下游的下单.分拣.配送到结算等整个环节.全流程数字化帮助生鲜配送企业互联网转型,有效提高 ...

  4. 探花交友_第1章_项目介绍以及实现登录功能_第1节_功能介绍

    探花交友_第1章_项目介绍以及实现登录功能_第1节_功能介绍 文章目录 探花交友_第1章_项目介绍以及实现登录功能_第1节_功能介绍 1.功能介绍 1.1.功能列表 1.2.注册登录 1.3.交友 1 ...

  5. 日月神话_常见的Java神话

    日月神话 这些问题在任何面试中都可能太过高级而无法提出,因为它们可能会使候选人推迟. 不管怎样,他们可能会在您自己的时间练习. 误解1)System.exit(0)阻止最终被调用 为什么这样的代码 S ...

  6. 人月神话贯彻执行_人月神话阅读笔记01

    本篇是人月神话阅读笔记的第一篇. 1-8章 1.焦油坑 焦油坑的意思说明了即使你足够强大,也无法摆脱束搏而沉到坑底. 可供大部分人使用的软件开发起来可不是一件简单的事情 乐趣与苦恼是这个行业避不开的话 ...

  7. 西西弗神话_表演神话

    西西弗神话 Performance optimization is the Rodney Dangerfield of web development–it "don't get no re ...

  8. 人月神话_神话般的代码

    人月神话 考虑以下代码段: int max = 10; int a = 0; while (true) {// do a thing that may result in an early retur ...

  9. 代码大全和新月神话_神话般的代码

    代码大全和新月神话 考虑以下代码段: int max = 10; int a = 0; while (true) {// do a thing that may result in an early ...

  10. dnf如何快速拾取物品_来个神话礼盒?DNF智慧的模拟机小游戏介绍

    DNF智慧的模拟机是之前在DFO国际服上线的小活动,这次几乎是原封不动的来到了国服,奖励上面会有所区别,但是具体玩法也非常简单,你可以把它看做是一个放置挂机类小游戏. 参与小游戏 点击运行模拟机就可以 ...

最新文章

  1. 邬贺铨院士:十问边缘计算!
  2. java对于数组的定义_Java中方法的定义与使用,以及对数组的初步了解。
  3. handler回调主线程_Android使用Handler实现子线程与子线程、子线程与主线程之间通信...
  4. SDM450+android8.1播放左声道音频文件和右声道音频文件,左右喇叭都有声音问题
  5. Spring @Configuration – RabbitMQ连接
  6. 递归 和 迭代 斐波那契数列
  7. OpenCL 第8课:旋转变换(2)
  8. iis7php怎么301重定向,iis7/8设置网站301重定向的方法
  9. C语言各种排序算法(冒泡排序、快速排序、插入排序、希尔排序、快速排序、 归并排序)
  10. sql 时态表的意义_SQL Server中的时态表
  11. 一些VC的快捷键以及调试技巧
  12. python的传参是传值还是传址
  13. 【渝粤教育】广东开放大学 服务标准化 形成性考核 (41)
  14. IDEA配置方法注释模板
  15. 最后的最后的一场考试
  16. OSChina 周日乱弹 ——给苹果电脑选机械键盘
  17. .find()的用法
  18. Xshell 6的 InstallShield: 1628 完成基于脚本的安装失败
  19. 通达信波段王指标公式主图_通达信波段专用主图指标公式
  20. python: 字符串转浮点数

热门文章

  1. ASP.NET开发学习视频教程大全(共800集)
  2. 大数据:海量数据的存储方案及其对应的高并发解决方案
  3. 如何自己打印计算机准考证,如何打印计算机准考证
  4. cs1.6的c语言源代码,cs1.6source - 源码下载|游戏|其他游戏|源代码 - 源码中国
  5. 记:用notepad2替换系统自带记事本notepad
  6. 完成中国福利彩票快三的程序设计
  7. 心电图分析软件_窦性P波形态突变或多变的心电图分析
  8. 国内太极AI智能交易系统
  9. c语言编程中的幂函数如何编写,c语言幂函数_C语言循环与递归实现整数幂函数...
  10. Bootstrap 插件-可切换导航栏