同一线程
同一线程
同线程是一种并发模型,其中单线程系统可扩展到N个单线程系统。结果是N个单线程系统并行运行。
同一个线程的系统不是纯粹的单线程系统,因为它包含多个线程。但是-每个线程都像单线程系统一样运行。因此,术语“ 同线程”而不是“单线程”。
为什么选择单线程系统?
您可能想知道为什么今天有人会设计单线程系统。单线程系统之所以流行,是因为其并发模型比多线程系统简单得多。单线程系统不与其他线程共享任何状态(对象/数据)。这使单线程可以使用非并发数据结构,并更好地利用CPU和CPU缓存。
不幸的是,单线程系统不能完全利用现代CPU。现代CPU通常会多带2、4、6、8个内核。每个内核都充当一个单独的CPU。单线程系统只能使用其中一个内核,如下所示:
同线程:单线程横向扩展
为了利用CPU中的所有内核,可以扩展单线程系统以利用整个计算机。
每个CPU一个线程
同线程系统通常在计算机中每个CPU运行1个线程。如果计算机包含4个CPU或具有4个内核的CPU,则通常会运行4个相同线程系统的实例(4个单线程系统)。下图显示了这一原理:
没有共享状态
同一个线程的系统看起来类似于传统的多线程系统,因为同一个线程的系统内部有多个线程在运行。但是有细微的差别。
同一线程系统与传统多线程系统之间的区别在于,同一线程系统中的线程不共享状态。没有线程并行访问的共享内存。没有线程共享数据的并发数据结构等。此处说明了这种差异:
缺少共享状态是导致每个线程在单线程系统下的行为。但是,由于同一个线程的系统可以包含多个线程-它实际上不是“单线程系统”。在没有更好的名字的情况下,我发现将这样的系统称为同线程系统而不是“具有单线程设计的多线程系统” 更为精确。同线程更容易说,也更容易理解。
从本质上讲,同一线程意味着数据处理停留在同一线程内,并且同一线程系统中没有线程可以同时共享数据。有时,这也被称为 没有共享状态并发或单独的状态并发。
负载分配
显然,同一个线程的系统需要在运行的单线程实例之间共享工作负载。如果只有一个线程可以完成任何工作,则该系统实际上将是单线程的。
究竟如何在不同线程上分配负载取决于系统的设计。我将在以下各节中介绍一些内容。
单线程微服务
如果您的系统包含多个微服务,则每个微服务都可以单线程模式运行。当您将多个单线程微服务部署到同一台计算机上时,每个微服务都可以在单个CPU上运行单个线程。
微服务本质上不共享任何数据,因此微服务是同线程系统的一个很好的用例。
分片数据服务
如果您的系统确实确实需要共享数据,或者至少需要共享一个数据库,则可以对数据库进行分片。分片意味着将数据分为多个数据库。通常对数据进行划分,以使彼此相关的所有数据一起位于同一数据库中。例如,属于某个“所有者”实体的所有数据都将插入同一数据库中。但是,分片不在本教程的讨论范围之内,因此您必须搜索有关该主题的教程。
线程通讯
如果同一线程系统中的线程需要通信,则通过消息传递来实现。如果线程A要向线程B发送消息,则线程A可以通过生成消息(字节序列)来发送消息。然后,线程B可以复制该消息(字节序列)并读取它。通过复制消息,线程B确保线程A在读取消息时无法修改消息。复制后,线程A无法访问消息副本。
通过消息传递进行的线程通信如下所示:
线程通信可以通过队列,管道,unix套接字,TCP套接字等进行。无论您的系统适合什么。
更简单的并发模型
在同一个线程系统中在其自己的线程中运行的每个系统都可以实现为单线程。这意味着内部并发模型变得比线程共享状态简单得多。您不必担心并发数据结构以及此类数据结构可能导致的所有并发问题。
例证
这是单线程,多线程和同线程系统的图示,因此您可以更轻松地了解它们之间的区别。
第一个插图显示了一个单线程系统。
第二个图显示了一个多线程系统,其中线程共享数据。
第三幅图显示了一个具有2个线程且具有单独数据的同线程系统,它们通过相互传递消息进行通信。
Java线程操作
Thread Ops for Java是一个开源工具包,旨在帮助您更轻松地实现单独的状态相同的线程系统。线程操作包含用于启动和停止单个线程以及通过单个线程实现某种程度的并发性的工具。如果您对使用相同线程的应用程序设计感兴趣,那么让Thread Ops看起来可能很有趣。您可以在我的Java线程操作教程中阅读有关线程操作的更多信息。