ECS编程和Pelagia比较

发表于2020-07-07
评论0 1.7k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏程序行业精英群

711501594

依赖和死锁问题

在介绍各种多线程开发工具前我先要介绍下多线程下最大的二个问题。

第一个问题就是任务执行的依赖关系。在不同线程间执行的任务代码会有先后次序的需求。但因为多线程的特性会导致这些代码被同时执行。那么需要一种方法来控制多线程间代码的依赖关系。违反这种依赖关系可能会导致数据的丢失。执行过程的严重错误。甚至崩溃,死机。

第二个问题就是死锁。在多线程执行过程中,多个线程会访问同一个数据。如果其中一个线程锁住了一个数据,然后请求另一个数据的锁。而其他线程刚好锁住了他请求中的数据,并也刚好请求他拥有的数据。就会导致两个线程互相等待系统卡死的问题。

为什么多线程下这两个问题是核心问题?

因为这两个问题的出现与多线程软件规模成正比,也就是说随着多线程软件规模的增加,这两个问题出现的概率也在增加。他们像达克摩斯之剑一样悬挂在任何多线程项目的上空。

 

POSIX Threads

POSIX Threads的标准文档地址:

https://standards.ieee.org/standard/1003_1c-1995.html

POSIX Threads也就是pthread是由IEEE协会在1995制定的C语言线程库标准。也是应用最广泛的多线程标准。这个库实现了基本的多线程编程接口。包括线程的创建,停止,加入等。也包括了互斥锁,信号,线程存储等功能。但windows系统并没有加入这个标准。其他操作系统对标准的实现也各不相同。但不可否认这是一个使用最广泛的库。虽然缺乏一些高级功能如消息队列和线程安全类型。

EglXvTNvY98x7cTshJhC.jpg

 

intel TBB

TBB是开源项目其地址为:

https://github.com/oneapi-src/oneTBB

 

Y1arCzfjhN2sEhnHH0T0.png

TBB是intel开发针对intel硬件优化的多线程库。看相关测试性能和使用pthread相近。这点让我有点困惑?不过TBB提供了大量高级功能的扩展,这点要比pthread强很多。

 

TBB的高级功能包括任务系统, 多线程安全的map, queue, vector等类型。以及parallel_for,parallel_while,parallel_reduce等并行算法。这些高级功能让开发并行软件更加容易。不过TBB只能使用在intel的硬件上。这局限了TBB的发展。

 

可以说TBB和POSIX Threads都是多线程开发的基本工具。学习的门槛非常高,需要使用者非常熟悉多线程的特性,才能针对不同的应用场景施展工具。这两款库是非常棒的多用途工具箱,但需要作为使用者的你是一个老师傅。这两款多线程库和其他的多线程库一样都只提供了多线程开发的基础功能,并没有解决多线程依赖和死锁的问题。

u4jp7Zp1OxkvP2qcyFDu.png

go语言

go是google推出的开发语言其地址为

https://golang.org/

 

goroutine 使go语言开发多线程就非常容易了。只要一句go func()就在线程内启动了一个任务。

 

package main

import "fmt"

 

func main() {

    messages := make(chan string)

    go func() { messages <- "ping" }()

    msg := <-messages

    fmt.Println(msg)

}

 

语法"messages := make(chan string)"则创建了一个消息队列用于接受和发送消息。 这个接受和发送消息也非常的简单只要使用关键字 "<-messages"和"messages <- "就可以实现。

 

go语言帮我们实现了自动的线程池和任务分配管理器。 但是GO语言没有实现对数据的分片和保护。也就是说GO语言通过使用自动的线程池, 任务分配管理器, 消息通信等方法。有效地解决了多线程中任务间依赖的问题。

 

但没有解决多线程中第二个问题,也就是死锁问题。这样导致随着任务数量的增加,数据锁的大量使用,死锁的概率也大幅增加。如果使用GO语言没有出现死锁。哪仅仅是因为你的软件规模还不够大,或则参与开发的人员不够多。

6JbuuWTx1twFzvyBKneS.jpg

ECS框架

是unity推荐的开源项目。

其项目地址在https://github.com/sschmid/Entitas-CSharp

 

ECS将数据划分为多个entry, 并保证每个entry每次只有一个system可以使用。 这样就保证不会产生数据的死锁。但其缺乏消除多线程依赖的治理手段。可会导致多个线程中发送次序问题。

 

例如,两个任务都依赖一个物品, 当其中一个任务完成销毁了物品, 记录在物品上的状态丢失, 就会导致另一个任务状态混乱甚至无法执行.

 

也就是说在一个时间内的updata中一个system如果修改了另一个system的数据。如果因为执行次序的原因在这个时间片内没有执行。那么在下个时间片这个数据有可能被删除或修改导致执行失败。因为ECS没有专门针对跨多线程的通信机制。来保留这些有调整依赖关系的数据。

 

ECS是以数据导向的时间分片机制,这个机制下不需要任何锁就可以调度多线程中的任务。为了偏执的不引入多线程锁,因为没有锁就肯定不会有死锁的问题。所以ECS未来也不可能引入以多线程锁队列为基础的消息通信机制。所以ECS的逻辑依赖问题是个无解的问题。这样就导致ECS虽然功能非常强大,但难以驾驭像极了苏联暴力美学的地效飞行器。

gj8vSLi0BZAXmLUgPjZG.jpeg

pelagia

是开源项目其地址在https://github.com/surparallel/pelagia

 

pelagia是由surparallel open source推出的开源项目,唯一同时解决依赖和死锁的lock-free的多线程工具。

在前面我简单的介绍了多线程工具的现状。我们知道依赖和死锁是多线程开发中必须要解决的两个问题。并不是简单的因为依赖和死锁会有概率的出现在多线程项目中。而是因为在多线程项目中存在指数规模效应的问题。

 

所谓指数规模效应是指假设一个项目有两个线程,如果你新添加一个线程,那么两个线程间发生依赖和死锁,就有3的2次方即9种可能。如果有99个线程,你同样是新添加一个线程,那么发生依赖和死锁的可能就变成了100的2次方种可能。也就是说可能发生依赖和死锁的状况,随着开发任务的增加成指数级别的增加。

这样就导致每开发一个新的线程任务就要和其余的线程任务做仔细的检查。检查是否可能出现依赖和死锁。而这种检查的规模也是程指数增加的。这样就导致我们开发的多线程项目很快就会达到团队所能承受的极限。

 

因为指数规模效应的存在就必然会有祖传代码拍死老师傅。为了避免老师傅们被祖传代码拍死。pelagia结合消息通信和数据分区两个技术,同时解决依赖和死锁问题,彻底拯救了老师傅。

 

pelagia目前处于准完成阶段。大部分功能已经开发完毕。包括消息通信的统计系统,支持多线程的日志系统,多线程数据分区的存储系统。其硬盘储存系统性能略快于redis。

5jwgnS4LRl2zemYBnBMz.jpg
  • 允许他人重新传播作品,但他人重新传播时必须在所使用作品的正文开头的显著位置,注明用户的姓名、来源及其采用的知识共享协议,并与该作品在磨坊上的原发地址建立链接
  • 可对作品重新编排、修改、节选或者以作品为基础进行创作和发布
  • 可将作品进行商业性使用

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

游戏学院公众号二维码
腾讯游戏学院
微信公众号

提供更专业的游戏知识学习平台