当前位置: 首页 > news >正文

skynet 游戏服务器探索(1)--熟悉skynet(网络)

因为做游戏服务器开发,大多数都跟脚本打交道,要么是lua,要么是python,要么是php,方便热更新的只有lua与php, php相关的游戏服务器开发,参考我另外的文章

https://blog.csdn.net/guoyilongedu/article/details/121049511

lua脚本相关的,自己也实现了一套,只不过不支持多线程,单进程的,基于libevent与luajit,上线过两款游戏项目,功能是挺全的,支持mysql,redis,定时任务相关。后面会贴出来,一起参考一下。

学skynet,因为skynet太出名了,是所有游戏服务器开发人员都绕不过去的,有必要或多或少熟悉一些,最好能自己动手实操一下,才能真正感受到skynet的魅力。

https://github.com/cloudwu/skynet

下载zip 文件,解压

cd skynet    #进入skynet目录
make linux    #编译

注意 因为skynet 用到c++11 相关的特性,所以gcc 必须支持C++11,所以版本必须大于4.9

初始怎么用 参考这篇文章

https://blog.csdn.net/qq_37717687/article/details/121766657

我们要关注的是游戏服务器的搭建,所以第一步 我们要关注的skynet 网络功能

之前用上面链接里面的一个echo 例子 试了一下,发现 一个问题 ,读取出来的数据包不完整 ,代码如下

local skynet = require "skynet"
local socket = require "skynet.socket"local clients = {}function connect(fd, addr)--启用连接,开始等待接收客户端消息print(fd .. " connected addr:" .. addr)socket.start(fd)clients[fd] = {}--消息处理while true dolocal readdata = socket.read(fd) --利用协程实现阻塞模式--正常接收if readdata ~= nil thenprint(fd .. " recv " .. readdata)for k,v in pairs(clients) do --广播socket.write(k, readdata)end--断开连接else print(fd .. " close ")socket.close(fd)clients[fd] = nilend    end
endskynet.start(function()local listenfd = socket.listen("0.0.0.0", 8888) --监听所有ip,端口8888socket.start(listenfd, connect) --新客户端发起连接时,conncet方法将被调用。
end)

这就很要命,研究了一下,是因为 skynet 的网络消息格式是固定的 2字节头(消息长度)+消息内容。

skynet 网络相关的是流式读取,也就是尝试读取的,一个数据包过来,可能要读好几次,至于为什么这么设计,可能是与内存池有关,内存池的分配都是按块的,所以才分批读取,后面单独再研究

单个socket每次从内核尝试读取的数据字节数为sz(第6行),这个值保存在s->p.size中,初始是MIN_READ_BUFFER(64b),当实际读到的数据等于sz时,sz扩大一倍(8-9行);如果小于sz的一半,则设置sz为原来的一半(10-11行)。

比如,客户端发了一个1kb的数据,socket线程会从内核里依次读取64b,128b,256b,512b,64b数据,总共需读取5次,即会向gateserver服务发5条消息,一个TCP包被切割成5个数据块。第5次尝试读取1024b数据,所以可能会读到其他TCP包的数据(只要客户端有发送其他数据)。接下来,客户端再发一个1kb的数据,socket线程只需从内核读取一次即可。

https://www.cnblogs.com/cnxkey/articles/15945319.html

static int
forward_message_tcp(struct socket_server *ss, struct socket *s, struct socket_lock *l, struct socket_message * result) {int sz = s->p.size;char * buffer = MALLOC(sz);int n = (int)read(s->fd, buffer, sz);if (n<0) {FREE(buffer);switch(errno) {case EINTR:break;case AGAIN_WOULDBLOCK:skynet_error(NULL, "socket-server: EAGAIN capture.");break;default:// close when errorforce_close(ss, s, l, result);result->data = strerror(errno);return SOCKET_ERR;}return -1;}if (n==0) {FREE(buffer);force_close(ss, s, l, result);return SOCKET_CLOSE;}if (s->type == SOCKET_TYPE_HALFCLOSE) {// discard recv dataFREE(buffer);return -1;}stat_read(ss,s,n);if (n == sz) {s->p.size *= 2;} else if (sz > MIN_READ_BUFFER && n*2 < sz) {s->p.size /= 2;}result->opaque = s->opaque;result->id = s->id;result->ud = n;result->data = buffer;return SOCKET_DATA;
}

第一次读取的字节 就是 #define MIN_READ_BUFFER 64

每次读满之后,字节扩大一倍

 if (n == sz) {s->p.size *= 2;
}

了解了这里 发现 改成如下这样

local skynet = require "skynet"local socket = require "skynet.socket"
local protobuf = require "protobuf" 
local cjson = require "cjson"local clients = {}
local logic_service = nil-- skynet.register_protocol {-- name = "client",-- id = skynet.PTYPE_CLIENT,    -- unpack = skynet.tostring,   --- 将C point 转换为lua 二进制字符串
-- }function connect(fd, addr)-- 启用连接 开始等待接收客户端消息print(" fd = ".. fd .. " connected addr:" .. addr)socket.start(fd)clients[fd] = {}-- 消息处理 不断循环接收while true dolocal readdata = socket.read(fd) -- 利用协程实现阻塞模式-- 正常接收if readdata ~= nil then--local ret_data = "fd = " .. fd .. " ==> " .. string.byte(readdata, 2);--readdata = string.unpack('>', readdata);print("-----------> ret_data " .. readdata);local s = readdata:byte(1) * 256 + readdata:byte(2) --数据包的长度print(" s = " .. s)local s1 = readdata:byte(3) * 256 + readdata:byte(4) --base64的长度print(" s1 = " .. s1)-- local real_data = readdata:sub(5, 100);-- --local base64_data = string.unpack(">s2", real_data)-- print("-----------> ret_data " .. real_data);--readdata = skynet.tostring(readdata)--local data_tb = protobuf.decode("cs.Person", readdata)--print(data_tb)--print(data_tb.name)-- print(data_tb.id)-- for _,v in ipairs(data_tb.phone) do-- print("\t" .. v.number, v.type)-- end--print(fd .. " recv " .. readdata)--local ret_data = "fd = " .. fd .. " ==> " .. readdata;if logic_service ~= nil thenlocal msg_tb = {}msg_tb['fd'] = fdmsg_tb['content'] = readdata;local stringbuffer = protobuf.encode("cs.Person", { name = "linsh", id = 1,email = readdata,}) -- 发送protobuf 数据local ret_msg_protobuf = skynet.call(logic_service, "lua", "doMsg_protobuf_data", stringbuffer)--ret_data = "fd = " .. fd .. " ==> " .. ret_msglocal ret_tb = protobuf.decode("cs.Person", ret_msg_protobuf)print(ret_tb.name)print(ret_tb.id)for _,v in ipairs(ret_tb.phone) doprint("\t" .. v.number, v.type)endret_data = cjson.encode(ret_tb)print(" ret msg from logic_service fd = " .. fd .. " ==> " .. ret_data)endif fd % 2 == 1 thenskynet.sleep(1000)endfor k, v in pairs(clients) dosocket.write(k, ret_data)end-- 断开连接else print(fd .. "close")socket.close(fd)clients[fd] = nilendend
endlocal CMD = {}function CMD.broad_msg_to_user(source, msg_content)print("=========> " .. msg_content)for k, v in pairs(clients) dosocket.write(k, msg_content)end
endskynet.start(function()logic_service = skynet.newservice("logic")local listenfd = socket.listen("0.0.0.0", 8888) -- 监听所有ip,端口8888socket.start(listenfd, connect) --新客户端发起连接时,conncet方法将被调用protobuf.register_file "./examples/protos/Person.pb" skynet.error("register:Person.pb") skynet.dispatch("lua", function(session, source, cmd, ...)local f = assert(CMD[cmd])-- f(source, ...)f(source, ...)end)end)

发现读取时,还是不行, 读取出来的总是不完整,了解到skynet 是分批读取,必须这些分批读取拼接起来,组成一个完整的数据包,所以需要一个netpack的中间层 来拼接数据包

--[[
协议分析:长度信息法
skynet提供的C语言编写的netpack模块,它能高效解析2字节长度信息的协议
]]local skynet = require "skynet"
local socketdriver = require "skynet.socketdriver"
local netpack = require "skynet.netpack"--不能同时包含socketdriver和socket,因为socket里已经register_protocol了socket类型
-- local socket = require "skynet.socket"local queue -- message queue
local clients = {}--解码底层传来的SOCKET类型消息
function socket_unpack(msg, size)return netpack.filter(queue, msg, size)
end--处理底层传来的SOCKET类型消息
function socket_dispatch(_, _, q, type, ...)skynet.error("socket_dispatch type:" .. (type or "nil"))queue = qif type == "open" thenprocess_connect(...)    elseif type == "data" thenprocess_msg(...)    elseif type == "more" thenprocess_more(...)elseif type == "close" thenprocess_close(...)elseif type == "error" thenprocess_error(...)elseif type == "warning" thenprocess_warning(...)end    
end--有新连接
function process_connect(fd, addr)skynet.error("new conn fd:" .. fd .. " addr:" .. addr)socketdriver.start(fd)    clients[fd] = {}clients[fd].last_time = skynet.time()
end--关闭连接
function process_close(fd)skynet.error("close fd:" .. fd)if clients[fd] thenclients[fd] = nilend
end--发送错误
function process_error(fd, error)skynet.error("error fd:" .. fd .. " error:" .. error)if clients[fd] thenclients[fd] = nilend
end--发送警告
function process_warning(fd, size)skynet.error("warning fd:" .. fd .. " size:" .. size)
end--刚好收到一条完整消息
function process_msg(fd, msg, size)local str = netpack.tostring(msg, size)skynet.error("recv from fd:" .. fd .. " str:" .. str .. " size = " .. size)for k, v in pairs(clients) doskynet.error(" all fd = " .. k)if k ~= fd then--socket.write(k, msg_content)socketdriver.send(k, str)endendif fd % 2 == 0 then--skynet.sleep(1000)endsocketdriver.send(fd, str)clients[fd].last_time = skynet.time()end--收到多于1条消息时
function process_more()for fd, msg, size in netpack.pop, queue doprint("process_more = fd = " .. fd .. " size = " .. size)skynet.fork(process_msg, fd, msg, size) --开启协程,协程保证了process_msg执行的时序性end
endfunction check_clients(timeout)while true doskynet.sleep(timeout)local now_time = skynet.time()skynet.error(" check clients now time = " .. now_time)local gap_time = 0for k, v in pairs(clients) doskynet.error(" all fd = " .. k .. " last_time = " .. v.last_time)gap_time = now_time - v.last_timeif gap_time >= 30 thensocketdriver.close(k)--clients[k] = nil--socketdriver.shutdown(k)end--socketdriver.send(k, " hearbeat fd = " .. k)endend
endskynet.start(function ()--注册SOCKET类型信息skynet.register_protocol({name = "socket",id = skynet.PTYPE_SOCKET,unpack = socket_unpack,dispatch = socket_dispatch,})--注册Lua类型消息--开启监听local listenfd = socketdriver.listen("0.0.0.0", 8887)socketdriver.start(listenfd)skynet.fork(check_clients, 3000)
end)

这样就能完整收包 解包

客户端测试代码 python脚本 有粘包 也能正常解

import socket
import threading
import struct
import sys
#import Person_pb2global recvThreadExitdef recvMsg(socket_obj):while True:print(" recvThreadExit = " + str(recvThreadExit))if recvThreadExit == 1:breakret = str(obj.recv(1024))print("recv msg :")print(ret)if len(ret) == 0 :#obj.shutdown(socket.SHUT_RDWR)#obj.close()print("close ==>")break# person = Person_pb2.Person()
# person.name = "ayuliao"
# person.id = 6
# person.email = "xxx@xx.com"
#person.phone = "13229483229"
# person_protobuf_data = person.SerializeToString()
#print(f'person_protobuf_data: {person_protobuf_data}')recvThreadExit = 0obj = socket.socket()obj.connect(('192.168.1.200', 8887))recv_thread = threading.Thread(target=recvMsg, args=(obj,))
recv_thread.start()while True:#a = raw_input()#print(a)inp = raw_input("input string: ").strip(' ') if inp == "quit" :#obj.shutdown(socket.SHUT_RDWR)obj.close()recvThreadExit = 1print("sssssssssssssssssseeeeeeeeeee")break#print(inp)##obj.sendall(bytes(inp, encoding="utf-8"))print("len = " + str(len(inp)) )#fmt_str = ">1h1h1h" + str(len(inp)) + "s"fmt_str = ">1h" + str(len(inp)) + "s"print(fmt_str)send_data = struct.pack(fmt_str, len(inp), bytes(inp))print(send_data + " len = " + str(len(send_data)) )obj.send(send_data)#obj.send(send_data)#obj.send(send_data)#obj.send(send_data)#obj.send(send_data)if inp == "q":breakprint(" exti ==>")
sys.exit(3)

网络的一个坑点就是这个,切不可拿其他人的示例来用,要自己多测试。

相关文章:

skynet 游戏服务器探索(1)--熟悉skynet(网络)

因为做游戏服务器开发&#xff0c;大多数都跟脚本打交道&#xff0c;要么是lua,要么是python,要么是php,方便热更新的只有lua与php, php相关的游戏服务器开发&#xff0c;参考我另外的文章https://blog.csdn.net/guoyilongedu/article/details/121049511lua脚本相关的&#xff…...

select、poll、epoll

select、poll、epoll select int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int nfds&#xff1a;被select管理的文件描述符的个数&#xff0c;最大描述符编号1fd_set *readfds&#xff1a;读文件描述符集合fd_se…...

rollup的基本使用 基本配置与处理各种文件

rollup rollup是一个javascript的模块化打包工具 可以帮助我们编译小的代码到一个大的负载的代码中 比如一个库或者一个应用 rollup与webpack的区别 rollup主要针对ES Module进行打包 另外webpack通常可以通过各种loader处理各种各样的文件 以及处理他们的依赖关系 rollup更多…...

ubuntu-debian系-redhat系

debian系 包类型&#xff1a;.deb包 本地安装包安装工具&#xff1a;dpkg 本地包管理命令&#xff1a;dpkg -i package 安装包 dpkg -r package 卸载包 dpkg -l package 查看已安装包 远程安装包安装工具&#xff1a;apt / apt-get 远程包管理命令&#xff1a;apt-get apt-cac…...

Altium Designer 18中原理图DRC编译和PCB DRC检查-AD DRC

一、原理图编译 原理图检查的主要内容有&#xff1a; 1、元件位号冲突。也即多个元件编号相同&#xff0c;例如两个电容在原理图中都被命名为C2&#xff0c;显然肯定是无法生成PCB的。 2、网络悬浮。也即网络标号没有附着在电气走线上&#xff0c;一般这种是人操作失误&…...

zipfile — 访问 ZIP 压缩文件

zipfile — 访问 ZIP 压缩文件 1.概述 zipfile 模块可用于操作 ZIP 存档文件&#xff0c;.zip 是 PC 程序 PKZIP 推广的格式 2.测试数据 为了演示用&#xff0c;你需要创建以下三个文件 1.README.txt 内容如下&#xff0c;注意最后一行为空行 The examples for the zipfil…...

检查nmos管是否损坏

NCEP85T14 功率mos管为例 以NMOS举例&#xff0c;只用万用表二极管档测量MOS管的好坏-电子发烧友网 NMOS的D极和S极之间有一个寄生二极管&#xff0c;方向为S到D&#xff0c;利用二极管单向导电性以及MOS管导通时寄生二极管截止的特性&#xff0c;可以快速测量MOS好坏。 1、测…...

第七章 - 聚合函数(count,avg,sum,max,min)和一些数学函数

第七章 - 聚合函数使用别名 ascount() 计数avg() 平均值sum() 求和max() 最大值min() 最小值一些数学计算函数Abs()Cos()Exp()Mod()Pi()radians()Sin()Sqrt()Power()Ceil()Floor()使用别名 as 在SQL中可以使用 as 来为一个字段或者一个值设置新的别名下面聚合函数的使用中就会…...

Typescript的原始据类型和Any类型

最新的ECMAScript标准定义了8中数据类型: 7种原始类型&#xff1a; BooleanNullUndefinedNumberBigintStringSymbol和 Object 除 Object 以外的所有类型都是不可变的 (值本身无法被改变》。例如&#xff0c;与C语言不同JavaScript 中字符串是不可变的 (译注: 如&#xff0c;Ja…...

[python入门㊼] - python类的高级函数

目录 ❤ 类的高级函数 ❤ __str__ ❤ __getattr__ ❤ __setattr__ ❤ __call__ ❤ 类的高级函数 今天来为大家介绍几个类中的高级函数&#xff0c;它们也是类中的内置函数。通过使用它们&#xff0c; 会让我们在进行类开发的时候更加的顺手&#xff0c;接下来我们就…...

【Windows】使用Fiddler 工具对手机进行接口监听

目录 工具下载 配置Fidder 手机端获取证书 过滤指定接口 工具下载 CSDN下载地址 其他下载地址 配置Fidder 安装后&#xff0c;打开进入如下界面 在fiddler菜单项选择Tools -> Options -> HTTPS 勾选【Decrypt HTTPS traffic 】 下拉框默认&#xff1a;【from al…...

SpringCloudAlibab-nacos

一、介绍注册中心配置中心的整合SpringCloudAlibaba中文地址&#xff1a;https://github.com/alibaba/spring-cloud-alibaba/blob/2.2.x/README-zh.md下载地址&#xff1a;https://github.com/alibaba/nacos/访问&#xff1a;http://localhost:8848/nacos/二、使用1、添加依赖&…...

从一致性角度考虑推荐冷启动长尾推荐问题(二)

前言&#xff1a;在推荐系统中user&item emb往往是最重要的特征之一&#xff0c;在冷启动和长尾优化的工作中&#xff0c;往往也是优化的重点&#xff0c;相当一部分工作是围绕着emb优化展开&#xff0c;所以这里单独开了一章。4)emb分布一致性主要思路在于冷启内容emb和高…...

电脑c盘满了怎么清理,c盘空间清理

电脑c盘满了怎么清理&#xff1f;电脑C盘满了可能是因为您的操作系统、程序文件、下载文件、临时文件、垃圾文件等占用了太多的存储空间。所以&#xff0c;我们就需要进行一些操作和清理。 一.清理电脑C盘的方法 清理临时文件和垃圾文件。在Windows上&#xff0c;您可以使用系…...

vite的基本使用

vite 浏览器原生支持模块化 浏览器原生加载的缺点 1.必须明确的写上后缀名 2.如果某一个模块 加载跟多其他的js文件 那么这些js文件都需要被依次加载 浏览器需要将所有的js文件请求下来 发送跟多的http请求&#xff08;效率也是非常低的&#xff09; 3.如果代码中由typescrip…...

JavaScript 字符串(String) 对象

JavaScript 是一种流行的编程语言&#xff0c;可以用于开发各种 Web 应用程序和移动应用程序。在 JavaScript 中&#xff0c;字符串是一种非常常见的数据类型&#xff0c;可以使用 JavaScript 字符串&#xff08;String&#xff09;对象来处理。本文将详细介绍 JavaScript 字符…...

小知识点:Mac M1/M2 VMware Fusion 安装 Centos 7.9(ARM 64 版本)

最近换了 Mac M2 芯片的笔记本&#xff0c;用原来的 Centos 镜像安装虚拟机直接报错 “无法打开此虚拟机的电源&#xff0c;因为它需要使用 X86 计算机架构&#xff0c;而该架构与此 Arm 计算机架构主机不兼容。” 安装流程前置一、下载镜像二、安装虚拟机三、配置静态 IP四、安…...

Nginx 新增模块 http_image_filter_module 来实现动态生成缩略图

前言 通过 nginx 的 HttpImageFilterModule 模块裁剪过大的图片到指定大小&#xff0c;这个nginx自带的模块是默认关闭的&#xff0c;所以需要重新编译nginx加上此模块。 一、编译 nginx 1.查看 nginx 模块 由于nginx 是之前装好的&#xff0c;这里需要先看一下是否安装了H…...

detach,主线程终止后子线程会结束吗

此前&#xff0c;我对detach的理解是&#xff0c;当主线程退出后&#xff0c;子线程能够继续存在。实际上&#xff0c;当主线程退出后&#xff0c;子线程也随之结束了。先看一个例子&#xff1a; #include <iostream> #include <thread> #include <unistd.h>…...

2023年云计算的发展趋势如何?还值得学习就业吗?

一、2023年云计算的发展将迎来新篇章 随着政策的正式放开&#xff0c;2023年的经济开始慢慢复苏&#xff0c;云计算在疫情期间支撑了复工复产&#xff0c;那么在今年对于云计算发展的限制将进一步的放开。Gartner的数据显示&#xff0c;到2023年&#xff0c;全球公共云支出将达…...

ROS2 入门应用 请求和应答(C++)

ROS2 入门应用 请求和应答&#xff08;C&#xff09;1. 创建功能包2. 创建源文件2.1. 服务端2.2. 客户端3. 添加依赖关系4. 添加编译信息4.1. 添加搜索库4.2. 增加可执行文件4.3. 增加可执行文件位置5. 编译和运行1. 创建功能包 在《ROS2 入门应用 工作空间》中已创建和加载了…...

华为机试题:HJ73 计算日期到天数转换(python)

文章目录博主精品专栏导航知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方法2、print() &#xff1a;打印输出。3、整型int() &#xff1a;将指定进制&#xf…...

将springboot项目生成可依赖的jar,并引入到项目中

1、将springboot项目生成可依赖的jar包的方法 SpringBoot项目默认打包的是可运行jar包&#xff0c;也可以打包成不可运行的jar包。 能打成可运行的jar包是因为&#xff0c;Spring Boot 项目引入了 spring-boot-maven-plugin 依赖包。 spring-boot-maven-plugin具有repackage …...

小红书搜索关键词布局指南,这4种词一定要把握好

在小红书搜索关键词布局&#xff0c;是提升搜索推流的重要方法&#xff0c;今天跟你讲清楚小红书搜索关键词布局怎么做&#xff5e;做小红书的都知道&#xff0c;小红书的主要流量来源一个是推荐&#xff0c;另一个就是搜索&#xff0c;关键词决定了你的精准人群&#xff0c;那…...

安全研发人员能力模型窥探

能力 是一个比较抽象的概念&#xff0c;不同的行业、管理者、研发人员对能力的认知都会有差异。另外&#xff0c;作为研发团队的相应的职级定级、绩效考核的基础&#xff0c;一个“大家普遍认可”的能力的模型是非常重要的。这是比职级模型更高层的一个基本模型&#xff0c;所谓…...

【面试总结】Linux篇·操作及原理篇

【面试总结】Linux篇原理篇1.介绍一下inode2.说一下Linux系统的目录结构3.说一下Linux系统的文件类型4.如何在Linux上配置一个IP地址5.Linux负载是什么&#xff1f;6.Linux中的软链接和硬链接有什么区别&#xff1f;1.介绍一下inode 硬盘的最小存储单位是扇区(Sector)&#xf…...

C++中如何实现用异或运算找出数组中只出现一次的数字???

文章目录1、异或运算符的运算1、异或运算符的运算 问题描述&#xff1a; 给出一个指定的数组&#xff0c;只有一个数出现一次&#xff0c;剩下都出现两次&#xff0c;找出出现一次的数字。指定数组为[1,2,2,1,3,4,3]。 样例输出&#xff1a;4 #include<iostream> using…...

红黑树的历史和由来。

一个数组&#xff0c;1,2,3,4,5,...n; 一共n个数字。1、直接查找想要查询第n个数字&#xff0c;直接搜索&#xff0c;就是n次查询。ps:那么问题来了&#xff0c;这样查询也太慢了&#xff0c;有什么改进的呢&#xff1f;2、二分查找这个时候&#xff0c;二分查找更快。不过就是…...

蓝库云|制造业数字化转型为何转不动?资料处理很重要

数字化转型已经成为每个产业势在必行的课题&#xff0c;没有人会怀疑数字化技术与科技能解放的生产力能量&#xff0c;但为什么看似美好的愿景&#xff0c;实行起来却如此缓慢&#xff1f;蓝库云认为这是因为没有盖好「资料治理」的地基。 面对不断变化的法令规范要求&#xf…...

【python学习笔记】 :Lambda 函数

Lambda 函数是 Python 中的匿名函数。有些人将它们简称为lambdas&#xff0c;它们的语法如下&#xff1a; lambda arguments: expressionlambda 关键字可以用来创建一个 lambda 函数&#xff0c;紧跟其后的是参数列表和用冒号分割开的单个表达式。例如&#xff0c;lambda x: 2…...

wordpress站点维护/网络推广是做什么工作的

线程池threadpool介绍 (Introduction) 随着芯片制造商致力于通过增加时钟速度来增加处理器内核&#xff0c;开发人员需要利用现代CPU的功能。 我们做到这一点的方法之一是在软件中实现并行算法。 One recent task I needed to perform at home was to find and document large …...

优秀网站开发/产品设计公司

1. 解压Oracle11.1.0.6 for win32,然后点击setup 2.选择高级安装,下一步 3.选择企业版&#xff0c;下一步 4.修改Oracle基目录&#xff0c;也可以是默认&#xff0c;下一步 5.将状态复选框打上√&#xff0c;下一步 6.为新安装的oracle创建数据库&#xff0c;选择创建数据库&am…...

暗网网站有那些/网时代教育培训机构官网

方法一: 使用join的方法 >>> " ".join(["A","B","C","D"]) A B C D 方法二: 使用字符串格式化拼接 >>> "%ss age is %d" % ("Jerry", 18) "Jerrys age is 18" >>…...

丹东做网站/网页制作软件dw

EnableTaskWindows DisableTaskWindows 在Delphi中显示一个窗口有两种方式,模态方式显示&#xff08;ShowModal&#xff09;和非模态方式显示&#xff08;Show&#xff09;&#xff0c;模态方式显示窗口时,必须在自身关闭后才能使父窗口起作用&#xff0c;但有时我们想要实现一…...

pdf viewer wordpress/网络市场营销

http://edu.51cto.com/lesson/id-10135.html http://edu.51cto.com/lecturer/user_id-140924.html转载于:https://www.cnblogs.com/mover/p/3406629.html...

哪个网站生鲜配送做的好/世界杯数据分析

1、描述 python中isinstance()函数&#xff0c;是python中的一个内置函数&#xff0c;用来判断一个函数是否是一个已知的类型&#xff0c;类似type()。 2、语法 isinstance&#xff08;object,classinfo&#xff09; 参数&#xff1a; object:实例对象 classinfo&#xff1a;可…...