当前位置:网站首页>Kotlin coprocess analysis (III) -- understanding the context of coprocess

Kotlin coprocess analysis (III) -- understanding the context of coprocess

2022-07-24 07:58:00 catzifeng

Collaboration context ——CoroutineContext It is a very important link in the coordination process , You can say that , Almost the business capability of the whole cooperation process is completed by it .

Tell the truth , This source code is not very good-looking , It is also difficult to explain in detail , If you have any doubts in the next reading , Let's talk about learning .

One 、 Brief introduction CoroutineContext

The coroutine context is actually a aggregate , There can be many business-related Context, for example :Job, Objects used to control collaborative tasks ;Dispatcher, The object used to schedule the process thread .

In any process , Even including suspended functions , Can be obtained coroutineContext, adopt get() Method to get specific Context To do business .

Two 、CoroutineContext Data structure of

Understanding its data structure is a very important link , In this way, you can understand some of its normal operation , For example, it has appeared before :
context = SupervisorJob() + Dispatchers.Main What's going on? ,coroutineContext[Job] What has this done ?

As the first section says , CoroutineContext It's a aggregate , So what kind of set is this ? Let's take a look at his notes first :

Persistent context for the coroutine. It is an indexed set of Element instances.
An indexed set is a mix between a set and a map. Every element in this set has a unique Key.

translate This is an element called Element Set , A between set and map Set between , Any one of them element There is a unique Key.

Since this is a set , We read his directly “put” and get Method :

1.“put”( Learn more CoroutineContext Data structure of )

CoroutineContext Of “put” The method is not direct “put”,CoroutineContext Itself is a collection , In the realization of “put” when , It uses a trick —— rewrite “+ Number ” The operator :
put Method
1). This function is adding new CoroutineContext after , Will return a containing all contexts CoroutineContext( Here we need to understand it , It's similar to a linked list / Nodule of tree ).

2). First judge what you want to join context Is it EmptyCoroutineContext, If it's empty CoroutineContext, Go directly back to the current CoroutineContext.

3). If you join context No EmptyCoroutineContext, So call CoroutineContext.fold() Conduct “ Fold ” Join in .

4). Look at all fold() Implementation of function , All in all 3 It's about :EmptyCoroutineContextElement and CombinedContext, Come here , We need to simply look at the source code of these three types of related functions ( Don't look too much , Just look at fold function ).

Let's analyze... One by one :

1.1 EmptyCoroutineContext
public override fun <R> fold(initial: R, operation: (R, Element) -> R): R = initial

This is the best understood ,EmptyCoroutineContext.fold( arbitrarily Context) = arbitrarily Context
namely :EmptyCoroutineContext + arbitrarily Context = arbitrarily Context.

1.2 Element
public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =
            operation(initial, this)

This is easy to understand , Put... Directly By foldConext and own Context Put in operation in , see operation The operation of .
namely :

Element +  arbitrarily Context =  arbitrarily Context.fold(Element) =
{
      acc( Oneself Context),element( The goal is Context) ->
	return  After the operation CoroutineContext
}
1.2 CombinedContext

About CombinedContext Let's not look at it first fold() function , Look at the name first : It means to combine ( Two in one ) Of Context, It's kind of interesting , Let's first look at its constructor :

internal class CombinedContext(
    private val left: CoroutineContext,
    private val element: Element
) : CoroutineContext, Serializable

Read notes , It says this is a left linked list structure , Contains left Of CoroutineContext Elements , And your own Element(Element Inherited from CoroutineContext), Seeing here is actually almost a further understanding CoroutineContext Data structure of .

About it fold() function , Let's not watch it yet .

Now let's assume a scenario : arbitrarily Context( Inherited from Element, Hereinafter referred to as itself Context) + Any other Context( Inherited from Element, Hereinafter referred to as goals Context) What kind of process will it be ?

Combine the source code with the above 1.2 Element What is the result of addition? Let's analyze it together , Then I'll go operation What's in it :
 Insert picture description here
First look at operation What are the two parameters of ,acc == Oneself Context,element == The goal is Context

step 1: Oneself Context Remove The goal is Context, And return the removed CoroutineContext

step 2: Judge the removed CoroutineContext Is it EmptyCoroutineContext, If EmptyCoroutineContext, Then go straight back The goal is Context, What does that mean ?

Assume yourself Context And the target Context equal (Key equal ), Then the removed CoroutineContext == EmptyCoroutineContext, So there is no need to add , Return directly to the target Context.

Assume yourself Contxt And the target Context It's not equal , Then come to the next step

step 3: First look at the notes above , This operation is to make a person named ContinuationInterceptor Of Context Can always be in the last position , Easy and fast access ,

Here we assume the goal Context And myself Context None of them contain ContinuationInterceptor, that interceptor == null,

Finally, go straight back to CombinedContext(removed- Remove target Context After that Context, element- The goal is Context).

Guys , Read the source code here , You should already be very clear CoroutineContext Data structure of , Here I'll draw a picture , More clearly ( a key )
 Insert picture description here

2.get

CoroutineContext rewrite “get The operator ”:

public operator fun <E : Element> get(key: Key<E>): E?

There are also several implementations , Namely ElementCombinedContextEmptyCoroutineContext and ContinuationInterceptor, About ContinuationInterceptor I won't give you too much introduction here , This sum CoroutineContext Is independent of the data structure , Specific CoroutineContext Business capabilities .

1.1 EmptyCoroutineContext

Look at the source code directly :

public override fun <E : Element> get(key: Key<E>): E? = null

Because it is empty CoroutineContext, So go straight back null.

1.2 Element

Look at the source code directly :

public override operator fun <E : Element> get(key: Key<E>): E? =
         if (this.key == key) this as E else null

As the element itself , So direct judgment key Whether it is equal or not , If equal, return directly to itself CoroutineContext.

1.3 CombinedContext

As an important guest , Its source code is still very important :

override fun <E : Element> get(key: Key<E>): E? {
    
        var cur = this
        while (true) {
    
            cur.element[key]?.let {
     return it }
            val next = cur.left
            if (next is CombinedContext) {
    
                cur = next
            } else {
    
                return next[key]
            }
        }
    }

I think look at the source code , combining The picture drawn above It should be easy to understand its search order .

原网站

版权声明
本文为[catzifeng]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/204/202207221752386114.html