并发彩票3d字谜–并发不是并行

关于Kotlin彩票3d字谜以及并发与并行性有何不同

官方文档 将Kotlin彩票3d字谜描述为“用于异步编程及更多功能”的工具,尤其是彩票3d字谜应通过“异步或非阻塞编程”来支持我们。这到底是什么意思? “异步”与术语“并发”和“并行性”如何相关,我们在这种情况下也经常听到有关标签的信息。在本文中,我们将看到彩票3d字谜主要关注并发性,而不主要关注并行性。彩票3d字谜提供了复杂的方法,可以帮助我们构建代码以使其高度并发地执行,并且还可以实现并行性,但这并不是默认行为。如果您还不了解它们之间的区别,请不必担心,在本文中它会变得更加清晰。我包括在内的许多人都在努力正确地使用这些术语。让我们进一步了解彩票3d字谜以及彩票3d字谜与所讨论主题的关系。

(您可以在以下位置找到有关Kotlin彩票3d字谜的一般介绍 本文)

异步-编程模型

在过去的两年中,异步编程是我们一直在阅读和听到的很多话题。它主要指“事件的发生与主程序流无关”,也指“处理这些事件的方式”( 维基百科 )。异步编程的一个关键方面是这样一个事实,即异步启动的动作不会立即阻止程序并发生 同时。异步编程时,我们经常会发现自己触发了一些子例程,该子例程立即返回到调用方,以使主程序流继续运行而无需等待子例程的结果。一旦需要结果,您可能会遇到两种情况:1)结果已被完全处理并且可以被请求,或者2)您需要阻塞程序直到可用为止。这就是期货或承诺的运作方式。异步的另一个流行示例是反应流的工作方式如 反应式宣言:

反应系统依赖 异步消息传递 在组件之间建立边界,以确保松散耦合,隔离和位置透明。 [...]无阻塞通信允许收件人仅在活动时消耗资源,从而减少了系统开销。

总之,我们可以将在软件工程领域中定义的异步描述为支持非阻塞和并发编程的编程模型。我们分派任务以使程序继续执行其他操作,直到收到表明结果可用的信号为止。下图说明了这一点:

我们想继续读书,因此让机器为我们洗衣服。

免责声明:我拍了这张照片,还有以下两个图片 这个Quora帖子 同时也描述了所讨论的术语。

并发-关于结构

在了解了异步的含义之后,让我们看看 并发 是。正如许多人错误地认为的那样,并发并不是“并行”或“同时”运行事物。 Google工程师Rob Pike以在Go上的工作而闻名,他将并发描述为“独立执行任务的组合”,他强调并发实际上是关于 构建程序。这意味着并发程序可以同时处理多个正在进行的任务,而不必同时执行。可以按任意顺序交错处理所有任务的工作,如以下小图所示:

并发不是并行性。它试图分解我们不必同时执行的任务。其主要目标是 结构体 ,不是 并行性.

并行性-关于执行

并行性(通常被误称为并发)是关于多个事物的同时执行。如果并发与结构有关,那么并行性与多个任务的执行有关。我们可以说并发使并行性的使用更加容易,但是它甚至不是前提条件,因为我们可以 并行性 没有并发。

最后,正如罗伯·派克(Rob Pike)所描述的那样:“并发是一次处理很多事情。并行性是一次处理很多事情”。您可以在下面观看他的演讲“并发不是并行性” 的YouTube .

在并发和并行性方面的彩票3d字谜

彩票3d字谜是关于 并发 首先。它们提供了出色的工具,可让我们将任务分解为多个块,这些块默认情况下不会同时执行。一个简单的例子说明了这是Kotlin彩票3d字谜的一部分 文件资料:


fun main() = runBlocking<Unit> { val time = measureTimeMillis { val one = 异步的 { doSomethingUsefulOne() } val two = 异步的 { doSomethingUsefulTwo() } println(" 的 answer is ${one.await() + two.await()}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) return 29 }

的 example terminates in roughly 1000 milliseconds since both "somethingUseful" tasks take about 1 second each and we execute them 异步的 hronously with the help of the 异步的 彩票3d字谜 builder. Both tasks just use a simple non-blocking delay to simulate some reasonably long-running action. Let's see if the framework executes these tasks truly simultaneously. 的 refore we add some log statements that tell us the 线 s the actions run on:

[main] DEBUG logger - in runBlocking
[main] DEBUG logger - in doSomethingUsefulOne
[main] DEBUG logger - in doSomethingUsefulTwo

Since we use runBlocking from the main 线 , it also runs on this one. 的 异步的 builders do not specify a separate 彩票3d字谜范围 要么 彩票3d字谜上下文 and therefore also inherently run on main.
We have two tasks run on the same 线 , and they finish after a 1-second delay. That is possible since delay only suspends the 彩票3d字谜 and does not block main. 的 example is, as correctly described, an example of 并发, not utilizing 并行性. Let's change the functions to something that really takes its time and see what happens.

并行彩票3d字谜

Instead of just delaying the 彩票3d字谜, we let the functions doSomethingUseful calculate the 下一个可能的素数 based on a randomly generated BigInteger which happens to be a fairly expensive task (since this calculation is based on a random it will not run in deterministic time):

fun doSomethingUsefulOne(): BigInteger {
    log.debug("in doSomethingUsefulOne")
    return BigInteger(1500, Random()).nextProbablePrime()
}

Note that the suspend keyword is not necessary anymore and would actually be misleading. 的 function does not make use of other suspending functions and blocks the calling 线 for the needed time. Running the code results in the following logs:

22:22:04.716 [main] DEBUG logger - in runBlocking
22:22:04.749 [main] DEBUG logger - in doSomethingUsefulOne
22:22:05.595 [main] DEBUG logger - Prime calculation took 844 ms
22:22:05.602 [main] DEBUG logger - in doSomethingUsefulOne
22:22:08.241 [main] DEBUG logger - Prime calculation took 2638 ms
Completed in 3520 ms

As we can easily see, the tasks still run 同时 as in with 异步的 彩票3d字谜 but don't execute at the same time anymore. 的 overall runtime is the sum of both sub-calculations (roughly). After changing the suspending code to blocking code, the result changes and we don't win any time while execution anymore.


注意示例

Let me note that I find the example provided in the 文件资料 slightly misleading as it concludes with "This is twice as fast, because we have 同时 execution of two 彩票3d字谜" after applying 异步的 彩票3d字谜 builders to the previously sequentially executed code. It only is "twice as fast" since the 同时 executed 彩票3d字谜 just delay in a non-blocking way. 的 example gives the impression that we get "并行性" for free although it's only meant to demonstrate 异步的 hronous programming as I see it.


现在如何使彩票3d字谜并行运行?为了从上面修复主要示例,我们需要在一些工作线程上分派这些任务,以不再阻塞主线程。我们有几种方法可以完成这项工作。

使彩票3d字谜并行运行

1.跑步 GlobalScope

We can spawn a 彩票3d字谜 in the GlobalScope. That means that the 彩票3d字谜 is not bound to any Job and only limited 通过 the lifetime of the whole application. That is the behavior we know from spawning new 线 s. It's hard to keep track of global 彩票3d字谜, and the whole approach seems naive and error-prone. Nonetheless, running in this global scope dispatches a 彩票3d字谜 onto Dispatchers.Default,由kotlinx.coroutines库管理的共享线程池。默认情况下,此调度程序使用的最大线程数等于可用的CPU内核数,但至少为两个。

Applying this approach to our example is simple. Instead of running 异步的 in the scope of runBlocking, i.e., on the main 线 , we spawn them in GlobalScope:

val time = measureTimeMillis {
    val one = GlobalScope.async { doSomethingUsefulOne() }
    val two = GlobalScope.async { doSomethingUsefulTwo() }
}

的 output verifies that we now run in roughly max(time(calc1), time(calc2)):

22:42:19.375 [main] DEBUG logger - in runBlocking
22:42:19.393 [DefaultDispatcher-worker-1] DEBUG logger - in doSomethingUsefulOne
22:42:19.408 [DefaultDispatcher-worker-4] DEBUG logger - in doSomethingUsefulOne
22:42:22.640 [DefaultDispatcher-worker-1] DEBUG logger - Prime calculation took 3245 ms
22:42:23.330 [DefaultDispatcher-worker-4] DEBUG logger - Prime calculation took 3922 ms
Completed in 3950 ms

我们成功地将并行性应用于了并发示例。正如我所说,此修复程序是幼稚的,可以进一步改进。

2.指定彩票3d字谜调度程序

Instead of spawning 异步的 in the GlobalScope, we can still let them run in the scope of, i.e., as a child of, runBlocking. To get the same result, we explicitly set a 彩票3d字谜 dispatcher now:

val time = measureTimeMillis {
    val one =  异步的 (Dispatchers.Default) { doSomethingUsefulOne() }
    val two =  异步的 (Dispatchers.Default) { doSomethingUsefulTwo() }
    println(" 的  answer is ${one.await() + two.await()}")
}

这种调整会导致与以前相同的结果,同时不会丢失我们想要的子级-父级结构。我们仍然可以做得更好。再次拥有真正的暂停功能不是最可取的吗?与其在执行阻塞函数时不注意不阻塞主线程,不如最好只调用不阻塞调用者的挂起函数。

3.使阻止功能挂起

我们可以用 withContext 它“立即从新上下文中应用调度程序,将块的执行转移到块内的其他线程中,并在完成时返回”

suspend fun doSomethingUsefulOne(): BigInteger = withContext(Dispatchers.Default) {
    executeAndMeasureTimeMillis {
        log.debug("in doSomethingUsefulOne")
        BigInteger(1500, Random()).nextProbablePrime()
    }
}.also {
    log.debug("Prime calculation took ${it.second} ms")
}.first

通过这种方法,我们将分派任务的执行限制在悬浮函数内部的质数计算中。输出很好地证明了,只有实际的素数计算发生在不同的线程上,而其他所有内容都保留在main上。多线程何时变得如此容易?我最喜欢这种解决方案。

(The function executeAndMeasureTimeMillis is a custom one that measures execution time and returns a pair of result and execution time)

23:00:20.591 [main] DEBUG logger - in runBlocking
23:00:20.648 [DefaultDispatcher-worker-1] DEBUG logger - in doSomethingUsefulOne
23:00:20.714 [DefaultDispatcher-worker-2] DEBUG logger - in doSomethingUsefulOne
23:00:21.132 [main] DEBUG logger - Prime calculation took 413 ms
23:00:23.971 [main] DEBUG logger - Prime calculation took 3322 ms
Completed in 3371 ms

注意:尽管我们不应该同时使用并发和并行性

如本文介绍部分中所提到的,我们经常使用术语并行性和并发性作为彼此的同义词。我想向您展示,即使Kotlin文档也没有明确区分这两个术语。关于“共享的可变状态和并发性”的部分(自2018年11月5日起,可能会在将来更改)介绍:

彩票3d字谜可以执行 同时 用一个 多线程调度程序 like the Dispatchers.Default. It presents all the usual 并发 problems. 的 main problem being synchronization of access to shared mutable state. Some solutions to this problem in the land of 彩票3d字谜 are similar to the solutions in the multi-threaded world, but others are unique.

这句话应该真正写成“彩票3d字谜可以在 平行 using 多线程调度程序s like Dispatchers.Default..."

结论

了解并发和并行性之间的区别很重要。我们了解到,并发主要是一次处理许多事情,而并行性则是一次执行许多事情。彩票3d字谜提供了复杂的工具来实现并发,但并没有免费提供并行性。在某些情况下,有必要将阻塞代码分发到某些工作线程上,以使主程序流程继续进行。请记住,对于CPU密集型和性能至关重要的任务,我们通常需要并行处理。在大多数情况下,最好不要担心并行性,而对我们从彩票3d字谜获得的出色的并发感到高兴。

最后,我要说谢谢您,在撰写本文之前,Roman Elizarov与我讨论了这些主题。🙏🏼

关于13条想法“并发彩票3d字谜–并发不是并行

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *