主协程和子协程执行顺序_协程任务执行器

主协程和子协程执行顺序

Featured in Kotlin Weekly Issue #214:

在Kotlin每周第214期中精选:

Since Kotlin is officially favored for Android development, we try to get to know what coroutine is and how it benefits us writing asynchronous code but in a sequential manner. Coroutine also emits its standardization figure where we are no longer faced with some of old school async approaches, e.g., Thread, Handler, or AsyncTask (So long, partner ~)².

由于Kotlin正式被Android开发所青睐,因此我们尝试了解什么是协程,以及它对我们以顺序方式编写异步代码的好处。 协程还散发出其标准化数字,使我们不再面对某些老式的异步方法,例如Thread,Handler或AsyncTask (很久以来,合作伙伴〜) ²。

介绍性 (Introductory)

Some may use coroutine in quite trivial needs like one-shot task, dispatching some heavy tasks to the background, and returning the result afterward, once each time it’s invoked. When complexity grows, however, there might be a need for how we can manage the ongoing coroutine task or the one to be executed in some specific situations.

有些程序可能会在非常琐碎的需求中使用协程,例如单次执行任务,将一些繁重的任务分派到后台,然后在每次调用时返回结果。 但是,当复杂性增加时,可能需要我们如何管理正在进行的协程任务或在某些特定情况下执行的任务。

Introducing the Executor of coroutine tasks (opinionated naming). One may interpret it as the one who will be managing the coroutine’s task. Executor is nothing but a bunch of abstracted basic patterns that we can make use of according to some specific needs without having the codebase getting cluttered by some of relative complex states.

介绍协程任务的执行程序(命名规则) 。 人们可能将其解释为将负责协程任务的人。 执行程序不过是一堆抽象的基本模式,我们可以根据一些特定的需求来使用它们,而不会使代码库因某些相对复杂的状态而混乱。

To get more real picture, say whenever there is a newer API request, we want to cancel the ongoing coroutine which holds the previous request so that we don’t need to handle the incoming obsolete response (whatever the actual reason is). Therefore, the executor will abstract the work for us.

为了获得更真实的图像,例如,每当有一个更新的API请求时,我们都想取消保存前一个请求的正在进行的协程,这样就无需处理传入的过时响应(无论实际原因是什么)。 因此,执行者将为我们摘要工作。

Below are defined executor types along with some of their use cases:

以下是定义的执行程序类型及其一些用例:

联合执行者 (ConflatedExecutor)

This type resembles the case I’ve introduced at glance previously. Imagine we’re developing a translator app and whenever the user is getting back to typing after stopping for some time millis, we would want to drop some ongoing previous API requests so that the app preserves the loading state instead of having last obsolete response shown up while the latest query has just been requested. This may cause ambiguity for the displayed translated result. Hence, we could assign this type to do the work since:

这种类型类似于我先前介绍的情况。 想象一下,我们正在开发一个翻译器应用程序,每当用户在停顿了一段时间后回到打字状态时,我们都希望删除一些正在进行的API请求,以便该应用程序保留加载状态,而不是显示最近的过时响应而刚刚请求了最新查询。 这可能会导致显示的翻译结果含糊不清。 因此,由于以下原因,我们可以分配此类型来执行工作:

ConflatedExecutor cancels any ongoing coroutine task and executes the latest one.

ConflatedExecutor取消任何正在进行的协程任务并执行最新的协程任务。

Now let’s magnify of what each line does:

现在让我们放大每一行的作用:

2ndSince we want to be capable of canceling any ongoing active task, we load the task inside another child coroutine. Hence, it results Job.

2 nd由于我们希望能够取消任何正在进行的活动任务,因此我们将该任务加载到另一个子协程中。 因此,结果为Job

We also wrap the Job with Atomic³ stuff since it benefits us for thread-safe: any updates made will be visible to other threads since they fetch from the memory.

我们还用Atomic Atom包装了Job ,因为它使我们受益于线程安全:由于其他线程从内存中获取数据,因此所做的任何更新对于其他线程都是可见的。

5thCreate the coroutine scope where we want to launch a new coroutine inside.

5在我们要在其中启动新协程的地方创建协程范围。

6thCreate a new coroutine, in this case, using async to create one since we want to return a value from the delegated task. We also want to start the coroutine LAZY⁴-ly to ensure any previous active coroutine gets canceled first.

6创建一个新的协程,在这种情况下,使用async创建一个协程,因为我们要从委派任务中返回一个值。 我们还想启动协程LAZY ly-ly,以确保首先取消任何先前的活动协程。

8thThis block gets invoked every time when an associated job completes or canceled. At this state, we should zero-out the atomic activeTask back once it’s no longer needed. Otherwise, memory leak could happen.⁵

8 thThis块被调用时,每一个相关的工作完成或取消的时间。 在这种状态下,一旦不再需要原子activeTask ,我们应该将其归零。 否则,可能会发生内存泄漏。 ⁵

14thHere we’re working with an aggressive tight loop to check if any active task/coroutine is ongoing. If none, we have the activeTask memorized the latest task.

14在这里,我们正在使用积极的紧缩循环,以检查是否正在进行任何活动任务/协程。 如果没有,则我们将activeTask记住最新的任务。

15thIf there’s any, we want to cancel them completely⁶ and avoid a possible tight loop on a single thread by yield⁷-ing on 15th.

15 THIF有任何,我们要取消他们完全 ⁶,避免对单个线程可能死循环的yield ⁷-ING 15日。

18thAfter every ongoing task is canceled, now we can start the delayed coroutine and await for the promised result.

18日在取消每个正在进行的任务之后,现在我们可以开始延迟的协程并await期望的结果。

QueueExecutor (QueueExecutor)

As the name implies, assume we’re doing a messaging app. Every time we tap the UI send button, it posts our message to an instance of what is called the “Message Broker” or similar ones to be processed in advance. In order guaranteeing the messages are posted in order (covering the case where the user presses the button in real quick), we want to assign the work for this type as:

顾名思义,假设我们正在做一个消息传递应用程序。 每当我们点击UI发送按钮时,它就会将我们的消息发布到所谓的“消息代理”或类似的实例中,以便提前进行处理。 为了保证消息按顺序发布(发现用户真正快速按下按钮的情况),我们希望将此工作分配为:

QueueExecutor will just queue up every incoming coroutine task and execute them FIFO-ly.

QueueExecutor只会将每个传入的协程任务排队,并按FIFO方式执行它们。

Take notes for the special concurrency type w̶h̶i̶c̶h̶ ̶y̶o̶u̶ ̶p̶r̶o̶b̶a̶b̶l̶y̶ ̶m̶i̶g̶h̶t̶ ̶h̶a̶v̶e̶n̶’̶t̶ ̶s̶e̶e̶n̶: the Mutex.

记下特殊并发类型wnotesh̶i̶c̶h̶̶y̶o̶u̶̶p̶r̶o̶b̶a̶b̶l̶y̶m̶i̶g̶h̶t̶̶h̶a̶v̶e̶n̶'̶t̶̶s̶e̶e̶n̶: 互斥体。

2ndIf we are previously familiar with synchronized or ReentrantLock, Coroutine’s alternative would be Mutex⁸. Mutex resembles just like a key where an instance needs to acquire it to enter the block. This guarantees only one request runs at a time.

2 NDIF我们以前熟悉的synchronizedReentrantLock ,协程的替代方案是Mutex ⁸。 Mutex就像一个键,实例需要获取它才能进入该块。 这样可以保证一次仅运行一个请求。

5thInstead of defining manually

5 thInstead手动定义的

The extension withLock has already abstracted those clauses away. At this state, the coroutines are lining up and in suspended state.

withLock扩展已经将那些子句抽象化了。 在此状态下,协程排成一行并处于悬浮状态。

6thNow we have the key (we’re inside the block), time to execute the delegated task.

6号现在我们有了钥匙(我们在代码块中),是执行委托任务的时间。

Note: Upon block completion by unlocking back the mutex, the key shall be passed to next inlined coroutine.

注意:通过解锁互斥锁完成块后,密钥应传递给下一个内联的协程。

并发执行器 (ConcurrentExecutor)

Nothing more but our typical daily practice.

只不过是我们的典型日常实践。

ConcurrentExecutor will just keep firing-up the coroutine tasks in parallel.

ConcurrentExecutor只会继续并行启动协程任务。

(Nothing fancy to be explained )

(没什么好解释的)

聚合器 (The Aggregator)

Regarding the above executor types, shouldn’t we need to reimport those related types every time we jump into similar use cases?

关于上述执行程序类型,我们是否每次进入类似用例时都不需要重新导入那些相关类型?

Well reflecting from personal practice, aggregating them into a central executor class will save the day. This central will then act as the dispatcher, assigning to which executor type based on a set of schemas.

从个人实践中很好地反映出来,将他们汇总到中央执行者课程中可以节省时间。 然后,该中心将充当调度程序,根据一组模式分配给哪种执行程序类型。

Yet we’re much easier appending when there are other new executor types, clients can still keep their business side clean by only interacting with the single aggregator’s execute API. Just delegate the task and select which schema for how one would like the task is getting executed.

但是,当有其他新的执行程序类型时,我们可以更轻松地进行添加,客户端仍然可以通过仅与单个聚合器的execute API进行交互来保持业务方面的清洁。 只需委派任务,然后选择要执行该任务的模式即可。

总结, (Sum Up,)

Having this executor concept could offer codebase a strong foundation¹ on how we want to control the coroutine task execution in some advanced ways. Those above-mentioned 3 types are just the starter pack to begin with and the companion aggregator provides us with a scalable space whenever there are other existing variants we want to enrich with.

具有这种执行程序概念可以为代码库奠定坚实的基础 ¹,以帮助我们以一些高级方式控制协程任务的执行。 上面提到的这3种类型只是入门包,伴随的聚合器为我们提供了可扩展的空间,只要我们想丰富其他现有的变体即可。

Alright, sharing is caring. Let’s share what other schemas you might have sparked with or if you have related questions, just leave the comments below. You can also view this sample project to give you more visual of each executor’s specialty. Thanks, hope this helps.

好吧,共享很重要。 让我们分享您可能引发的其他模式,或者如果您有相关问题,请在下面留下评论。 您还可以查看此示例项目,以使您更加直观地了解每个执行者的专长。 谢谢,希望对您有所帮助。

External links:

外部链接:

  1. https://github.com/ErickSumargo/Kirin

    https://github.com/ErickSumargo/Kirin

  2. https://developer.android.com/reference/android/os/AsyncTask

    https://developer.android.com/reference/android/os/AsyncTask

  3. https://www.baeldung.com/java-atomic-variables

    https://www.baeldung.com/java-atomic-variables

  4. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-l-a-z-y.html

    https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-lazy.html

  5. http://man.hubwiz.com/docset/Kotlin.docset/Contents/Resources/Documents/api/latest/jvm/stdlib/kotlin.native.concurrent/-atomic-reference/index.html

    http://man.hubwiz.com/docset/Kotlin.docset/Contents/Resources/Documents/api/latest/jvm/stdlib/kotlin.native.concurrent/-atomic-reference/index.html

  6. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel-and-join.html

    https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel-and-join.html

  7. https://www.lukaslechner.com/how-to-run-an-expensive-calculation-with-kotlin-coroutines-on-the-android-main-thread-without-freezing-the-ui/

    https://www.lukaslechner.com/how-to-run-an-expensive-calculation-with-kotlin-coroutines-on-the-android-main-thread-without-freezing-the-ui/

  8. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/

    https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/

翻译自: https://proandroiddev.com/coroutine-task-executor-916febd5c460

主协程和子协程执行顺序

你可能感兴趣的:(python)