2017-09-14 29 views
6

Một số khung công tác JVM sử dụng ThreadLocal để lưu trữ ngữ cảnh cuộc gọi của ứng dụng, như SLF4j MDC, người quản lý giao dịch, người quản lý bảo mật và những người khác.Cách sử dụng mã dựa trên ThreadLocal với các corlin của Kotlin

Tuy nhiên, các coroutines Kotlin được gửi đi trên các luồng khác nhau, vậy làm thế nào nó có thể được thực hiện để hoạt động?

(Câu hỏi đặt ra là lấy cảm hứng từ GitHub issue)

Trả lời

8

analog coroutine để ThreadLocalCoroutineContext.

Để tương thích với ThreadLocal-sử dụng thư viện bạn cần triển khai ContinuationInterceptor tùy chỉnh có hỗ trợ các chỉ đường cục bộ cụ thể theo khung.

Đây là một ví dụ. Chúng ta hãy giả sử rằng chúng ta sử dụng một số khuôn khổ dựa trên một cụ ThreadLocal để lưu trữ một số dữ liệu ứng dụng cụ thể (MyData trong ví dụ này):

val myThreadLocal = ThreadLocal<MyData>() 

Để sử dụng nó với coroutines, bạn sẽ cần phải thực hiện một bối cảnh mà giữ giá trị hiện tại của MyData và đặt nó vào tương ứng ThreadLocal mỗi khi coroutine được nối lại trên một sợi. Mã nên trông như thế này:

class MyContext(
    private var myData: MyData, 
    private val dispatcher: ContinuationInterceptor 
) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor { 
    override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = 
     dispatcher.interceptContinuation(Wrapper(continuation)) 

    inner class Wrapper<T>(private val continuation: Continuation<T>): Continuation<T> { 
     private inline fun wrap(block:() -> Unit) { 
      try { 
       myThreadLocal.set(myData) 
       block() 
      } finally { 
       myData = myThreadLocal.get() 
      } 
     } 

     override val context: CoroutineContext get() = continuation.context 
     override fun resume(value: T) = wrap { continuation.resume(value) } 
     override fun resumeWithException(exception: Throwable) = wrap { continuation.resumeWithException(exception) } 
    } 
} 

Để sử dụng nó trong coroutines, bạn quấn phối mà bạn muốn sử dụng với MyContext và đặt cho nó giá trị ban đầu của dữ liệu của bạn. Giá trị này sẽ được đưa vào thread-local trên thread nơi coroutine được nối lại.

launch(MyContext(MyData(), CommonPool)) { 
    // do something... 
} 

Việc thực hiện ở trên cũng sẽ theo dõi bất kỳ thay đổi đối với thread-địa phương đã được thực hiện và lưu trữ nó trong bối cảnh này, vì vậy cách nhiều gọi này có thể chia sẻ dữ liệu "thread-địa phương" qua ngữ cảnh.

Các vấn đề liên quan