首页 > 其他分享 >2-skynet基本概况

2-skynet基本概况

时间:2022-12-08 14:34:34浏览次数:62  
标签:基本 服务 thread 队列 概况 线程 skynet config

视频中的讲解和本系列博客是对应的,但不是完全相同的.

这一节主要是建立大致印象。暂时不要太纠结于细节

image-20220529093208589

问题:

  • 一个skynet进程里面总共有什么线程

  • 工作线程怎么工作的

  • 私有队列消息从哪里来的

//一个工作线程主要工作流程	
	
while(true)
	{
	    
	    queue = get_one_queue(global_queue) //通过全局队列拿到一个私有队列
	    
	    
        ctx  = get_ctx( queue->handle ) //通过队列拿到一个服务
	    
	    
	    msg = get_one_message(queue) //从队列里面取出一个消息
	       
	    
	    ctx->callback(msg) //调用服务的回调函数 ,在这个回调函数里面再调用一个固定的 lua函数
	   
	    
	}
	

一个skynet节点,也就是一个skynet进程。他启动的时候会创建多个线程,他们是

  • 网络线程
  • 定时器线程
  • 监听线程
  • 多个工作线程

上图中所示的每个队列其实都是关联一个服务的。所有的队列连接成一个大链表。服务的概念你可以对比医院来理解。比如今天有三个主治医生坐诊,他们都是看痔疮的,名字是张三李四王五。每个患者都在大厅等候,医生叫号的时候,就进去看病。比如你预约的张三医生,你的挂号单上面可能显示前面还有好几个人,也就是你要排队等着。那么张三医生叫你的时候,你就去他的问诊室看病。

这里张三医生就是一个服务。服务关联的队列就是排队找他看痔疮的同学。李四医生也是一个服务。张三和李四他们是没有关联的,各看各的患者。当然李四医生和张三医生本质上都是看痔疮的服务。需要多个服务的原因是,得痔疮的同学太多了。

再看看几个线程的主要功能

网络线程:

  • 接收skynet外部的网络请求,然后push到服务的队列。
  • 当服务需要把数据发送给外部时,实质上是 服务--->网络线程--->外部

定时器线程:把定时器消息push到某个服务。当服务在处理定时器消息时,就可以认为是定时器事件触发了。

监听线程:主要是发现工作线程有没有死循环。

工作线程:驱动服务处理消息

下面看代码。skynet进程的主函数入口是 skynet_main.c的main函数

int
main(int argc, char *argv[]) {
	const char * config_file = NULL ;
	skynet_globalinit();
	skynet_env_init();

	sigign();

	struct skynet_config config;



	struct lua_State *L = luaL_newstate();//生成luastate的目的主要是读取配置文件中的配置项
	luaL_openlibs(L);	// link lua lib

	int err =  luaL_loadbufferx(L, load_config, strlen(load_config), "=[skynet config]", "t");
	assert(err == LUA_OK);
	lua_pushstring(L, config_file);

	err = lua_pcall(L, 1, 1, 0);//执行配置文件

	_init_env(L);
	//把配置文件里面的配置项 都读出来
	config.thread =  optint("thread",8);
	config.module_path = optstring("cpath","./cservice/?.so");//默认路径下的动态链接库有gate.so  harbor.so  logger.so  snlua.so 常用snlua.so来创建模块实例
	config.harbor = optint("harbor", 1);//这里推荐在配置文件中设置为0 否则默认为1
	config.bootstrap = optstring("bootstrap","snlua bootstrap");//启动服务设置: snlua作为服务模块 bootstrap作为服务对应的lua文件
	config.daemon = optstring("daemon", NULL);//后台运行配置
	config.logger = optstring("logger", NULL);//保存日志的文件名字 这里日志的来源是lua层调用的skynet.error(str)
	config.logservice = optstring("logservice", "logger");//默认日志模块是 logger 即 service_logger.c 所代表的模块
	config.profile = optboolean("profile", 1);

	lua_close(L);

	skynet_start(&config);//next
	skynet_globalexit();

	return 0;
}

上面我们关注的是 main函数读取了一个 lua配置文件。这个配置文件就是你启动 skynet进程时使用的命令,类似 ./skynet config。 这里的config就是配置文件。

void 
skynet_start(struct skynet_config * config) {

	skynet_harbor_init(config->harbor);
	skynet_handle_init(config->harbor);//可以简单的认为就是保存了 handle和服务 映射关系的数组
	skynet_mq_init();//初始化一个全局队列 用来把所有服务关联的队列 连接起来
	skynet_module_init(config->module_path);//模块初始化
	skynet_timer_init();
	skynet_socket_init();

	skynet_profile_enable(config->profile);
	struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);//首先创建日志服务


	skynet_handle_namehandle(skynet_context_handle(ctx), "logger");//给日志服务绑定一个名字

	bootstrap(ctx, config->bootstrap);//创建bootstrp服务 注意这里服务并没有完成所有流程 因为工作线程还没有启动 服务的第一个消息只是push进队列了

	start(config->thread);//next


}

上面的代码主要是做了初始化工作和启动了两个服务。后面再细说服务。我们来看 start(config->thread)。这里主要就是启动了 监听线程 定时器线程 网络线程 和多个工作线程。

static void
start(int thread) {
	pthread_t pid[thread+3];

	struct monitor *m = skynet_malloc(sizeof(*m));//创建监听管理器
	memset(m, 0, sizeof(*m));
	m->count = thread;//数量跟工作线程数一致 工作线程数一般又设置成跟你的cpu核心数相同
	m->sleep = 0;

	m->m = skynet_malloc(thread * sizeof(struct skynet_monitor *));
	int i;
	for (i=0;i<thread;i++) {
		m->m[i] = skynet_monitor_new();//每个工作线程安排一个监听
	}
	
	create_thread(&pid[0], thread_monitor, m);//监听线程的职责是监听工作线程
	create_thread(&pid[1], thread_timer, m);//定时器线程
	create_thread(&pid[2], thread_socket, m);//网络线程


	struct worker_parm wp[thread];
	for (i=0;i<thread;i++) {
		create_thread(&pid[i+3], thread_worker, &wp[i]);//给每个工作线程传递不同参数
	}

}

到这里就算是完成了对skynet整体的简单理解

b站对应视频 https://www.bilibili.com/video/BV19d4y1678X

标签:基本,服务,thread,队列,概况,线程,skynet,config
From: https://www.cnblogs.com/waittingforyou/p/16965978.html

相关文章

  • vim基本使用
    vim基本使用使用方法在终端输入vim+(文件),如果文件已经存在,则使用vim打开文件,否则创建一个文件。或者,是输入vim直接进入,再输入:e+文件名,来打开文件。进入vim后默认为......
  • 1. 流程控制语句if基本概述
    1.流程控制语句if基本概述01.单分支结构if[如果你有房];then我就嫁给你fi#示例[root@qiudao~/shell]#catif-1.sh#!/usr/bin/bashifwhichls;thenecho"......
  • 前端开发:6、jQuery类库简介与基本使用
    jQuery类库目录jQuery类库一、简介二、jQuery查找对象1、选择器......
  • 设计模式预热篇——6大基本原则
         本篇博客主要是复习设计模式的时候,对6大设计原则的总结,参考书籍《设计模式之禅》,讲设计模式的经典之作。     java编程的6大设计原则如下:   ......
  • smail基本语法示例
    准备工作工欲善其事必先利其器,所以要学好smail语法,好的工具是必须的,这里推荐两个工具,一个是Smali2Java,也就是将smail文件转换成java的工具;另一个工具是J2S2J1.3,这个工具可......
  • jQuery 及 Bookstrap 基本使用
    今日内容总结jQuery查找标签1.基本选择器 $('#d1') id选择器 $('.c2') class选择器 $('div') 标签选择器2.组合选择器 $('div#d1') 查找id是d1的div标签......
  • 线性代数入门——第二讲 行列式基本性质
    上一讲我们了解了线性代数中行列式的基础知识,这一讲继续来学习行列式中的八个基本性质,并给出这些性质严谨的证明,学习行列式基本性质的目的是为了面对高阶行列式通过对性质......
  • ​Docker网络实现的基本原理
    Docker的网络实现基本原理是利用了Linux的网络命令空间和虚拟网络设备,因为Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包将......
  • Docker网络实现的基本原理
    Docker的网络实现基本原理是利用了Linux的网络命令空间和虚拟网络设备,因为Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包......
  • Vue基本语法
    v-bind我们成功创建了第一个Vue程序,看起来跟渲染一个字符串模板非常类似。但是Vue在背后做了大量工作。现在数据和DOM已经被建立了关联,所有东西都是响应式的。我们在......