初试PyOpenGL三 (Python+OpenGL)GPGPU基本运算与乒乓技术
这篇GPGPU 概念1: 数组= 纹理 - 文档文章提出的数组与纹理相等让人打开新的眼界与思维,本文在这文基础上,尝试把这部分思想拿来用在VBO粒子系统上.
在前面的文章中,我们把CPU的数据传到GPU后,然后就直接从桢缓冲到显示屏幕上了,那么还能不能把从GPU的数据拿回来放入CPU,然后进行处理。例如最基本的GPGPU编程中,把数组放入GPU运算后返回CPU。以及图片用GPU来加速处理。
和以前把数据从CPU通过相关GLSL,Cg着色器语言传入数据到GPU并进行处理不同,多了个返回数据到CPU中,因为GPU擅长的是并行处理,所以我们一般把一系列数据处理从CPU中交给GPU。在前面的顶点拾取中,获取地形高度中,我们都把一系列数据当做纹理,然后从CPU传入GPU中处理。现在关键问题是,如果把GPU数据送回到CPU中。
在前面这篇文章中(WebGL 利用FBO完成立方体贴图),我们看到前面,可以先在FBO里,把当前的内存数据经过GPU处理后输出到应用程序桢缓冲关联的纹理中,然后此纹理拿来做后面球所需要的立方体贴图。在这过程中,我们可以知道通过FBO实现,数据从CPU处理传入GPU,在着色器中进行处理后,然后我们可以在CPU中得到对应FBO中纹理里的数据。
下面我们完成一个简单实例,通过把一个数组,传入GPU中,在GPU中进行处理,然后返回到CPU中并显示出来。在这我们只介绍,数据一对一的处理,就是传入多少数据,返回多少数据。
结合上面所说,大致过程如下,第一步创建FBO,并关联一个纹理(存放经过GPU处理的数据),然后再创建一个纹理,里面用来存放我们需要处理的数据,因此要求,这个纹理和FBO中关联的纹理大小一样,方便处理。第二步,我们在创建的FBO中,来完成一个输出渲染,因为上步,要求相同大小的纹理,所以这个渲染窗口我们需要特殊处理下,在这窗口,最大保证窗口大小与纹理大小一样,纹理刚好占用整个窗口大小。这样才能保证输出到FBO中的纹理和传入的纹理索引一一对应。这样FBO中的纹理就存放的是原始数据经过GPU处理后的数据。
让我们来完成整个过程,首先,我们把转入的数据整理成我们需要的数组列表。请看代码如下:
def __init__(this,*args):
this.imageFormat = GL_FLOAT
if len(args) == 1 :
if isinstance(args[0],Image):
image = args[0]
this.width = image.size[0]
this.height = image.size[1]
this.data = image.im
this.imageFormat = GL_UNSIGNED_BYTE
if isinstance(args[0],list):
listf = args[0]
this.width = len(listf) if len(listf) > 0 else 1
this.height = 1
this.data = listf
if len(args) == 3:
this.width = int(args[0])
this.height = int(args[1])
this.data = args[2]
this.imagedata = []
for i in range(this.height):
for j in range(this.width):
index = i * this.width + j
f4 = this.data[index] if index < len(this.data) else float(j) / float(this.width)
r,g,b,a = 0.0,0.0,0.0,0.0
if isinstance(f4,tuple):
if len(f4) == 2:
r,g = f4
elif len(f4) == 3:
r,g,b = f4
else:
r,g,b,a = f4
else:
r = f4
this.imagedata.append(r)
this.imagedata.append(g)
this.imagedata.append(b)
this.imagedata.append(a)
#this.imagedata = ny.array(this.imagedata,dtype=ny.float)
#print this.imagedata
初始化
这段代码里,会列举几种情况,一种是直接传入的Image信息,还有是传入的自定义数组,还有定义了格式化长与宽的数组。然后结合传入数组的信息,可以是单个数据,也可以是如Image里保存的如r,g,b,a这样的四元组,整理后,得到我们需要的纹理的长与宽,纹理所保存的数据。
然后如上面的第一步中所说,创建一个FBO和与之关联的纹理,还有一个保存需要处理的数据的纹理。具体代码如下:
def createFBO(this):
this.fbo = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
#create texture for fbotext,GPU->CPU
this.fbotext = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D,this.fbotext)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this.width, this.height,0,GL_RGBA,GL_FLOAT,None)#GL_FLOAT
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
#relation fbo and fbotext(FBO and Texture2D)
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,this.fbotext,0) #glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,this.fbotext,0)
glBindFramebuffer(GL_FRAMEBUFFER,0)
#save data to texture.CPU->GPU
this.fbodata = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D,this.fbodata)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
print this.imageFormat
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this.width, this.height, 0, GL_RGBA,this.imageFormat, this.imagedata)
创建FBO与纹理
就如上面所说,创建FBO,二个纹理,其中纹理需要注意的是glTexImage2D中的第三个参数,这里我们选择的是GL_RGBA32F,这样可以在纹理中,对应的r,g,b,a通道保证存放完整的32位浮点数据,而不必要限制在0.0-1.0。下面这些参数按理说可以不设置,但是如果你传入的是图片,为了保证处理后的图片显示正常,还是有必要设置的。其中glTexImage2D的参数对应详细说明,如果大家有兴趣,可以自己搜索。
下面就如上面第二步所说,创建输出渲染,窗口需要与纹理大小一一对应,主要代码如下:
def renderFBO(this,shader):
glDisable(GL_DEPTH_TEST)
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
glPushAttrib(GL_VIEWPORT_BIT)#| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glDrawBuffer(GL_COLOR_ATTACHMENT0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0.0,this.width,0.0,this.height)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glViewport(0,0,this.width,this.height)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, this.fbodata)
glUseProgram(shader)
glUniform1i(shader.tex0, 0)
glUniform1f(shader.xl, this.width)
glUniform1f(shader.yl, this.height)
glBegin(GL_QUADS)
glVertex2f(0.0, 0.0)
glVertex2f(this.width, 0.0)
glVertex2f(this.width, this.height)
glVertex2f(0.0, this.height)
glEnd()
glUseProgram(0)
glBindFramebuffer(GL_FRAMEBUFFER,0)
输出数据并保存到FBO对应纹理上
嗯,我发现需要把对应的着色器代码一起贴出来,然后再好说明。请看对应的着色器代码如下:
gpgpu_v = """
//#version 330 compatibility
#version
out vec4 pos;
void main() {
pos = vec4(gl_Vertex);
//The following coding must be in fragment shader
//vec2 xy = v.xy;
//vec2 uv = vec2(xy/vec2(xw,yw)).xy;
//o_color = texture2D(tex0, uv);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}""" gpgpu_f = """
//#version 330 compatibility
#version
in vec4 pos;
uniform sampler2D tex0;
uniform float xw;
uniform float yw;
void main() {
vec2 xy = pos.xy;
vec2 uv = vec2(xy/vec2(xw,yw)).xy;
vec4 o_color = texture2D(tex0, uv);// vec4(uv.x,uv.y, 0, 1 );//
o_color = o_color + vec4(0.2);
gl_FragColor = o_color;
}"""
着色器
这二段代码就是主要的过程了,首先告诉OpenGL,我们用的是应用程序桢缓冲(glBindFramebuffer),是不输出到屏幕中的。首先就是把输出窗口和纹理大小一一对应,保证纹理刚好显示在一个满屏幕上,因此,在这我们用的投影矩阵是正投影矩阵,和透视投影矩阵的区别,这里就不详细说明,简单来说,透视投影会带给人如人眼中看到的远处的特殊显示比较少的效果,而正投影就是远处和近处大小显示不改变,他们主要就是对三维点xyz中的z值采用不同的处理造成的。而视图矩阵,和模型矩阵一样,他们不需要改变点的位置,直接采用单元矩阵就可。结合着色器中相应代码,简单来说,传入的长与宽,是用了得到相应顶点的索引值,这里相应代码在上文中的获取地形的高度一样的道理,这里不需要x,y二分量分别加0.5,是因为顶点一个是0-x,一个是(-x/2)-x/2.根据我们平常根据索引取数组里的值一样,只是多考虑成二维的情况。特意说下,相关过程据需要放入片断着色器中,因为我们是顶点和像素一一对应,只有在片断中,才是针对像素的处理。
下面我们来验证我们二个处理,看下能不能满足我们。一个是图片,我们把图片里的r,g,b,a分量分别加上0.2,这样看起来应该显示更亮一些。第二个我们是传入一个数组,然后按上面我们进行处理后,输出到控制台里面。
第一个,传入数据与相应改动如下(在上文与前面的基础上): 在gpgpubasic中,新增一个方法,主要是输出原始图片,与经过GPU在各分量上加上0.2处理后的图像。代码增加如下:
def render(this,shader):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0.0,this.width * 2,0.0,this.height * 2)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glViewport(0,0,this.width,this.height) glColor4f(1.0, 1.0, 1.0, 0.5)
glActiveTexture(GL_TEXTURE0)
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, this.fbodata)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex2f(0.0, 0.0)
glTexCoord2f(1.0, 0.0)
glVertex2f(this.width, 0.0)
glTexCoord2f(1.0, 1.0)
glVertex2f(this.width, this.height)
glTexCoord2f(0.0, 1.0)
glVertex2f(0.0, this.height)
glEnd() glTranslatef(this.width + 10, 0.0, 0.0)
glColor4f(1.0, 1.0, 1.0, 0.5)
glActiveTexture(GL_TEXTURE0)
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, this.fbotext)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex2f(0.0, 0.0)
glTexCoord2f(1.0, 0.0)
glVertex2f(this.width, 0.0)
glTexCoord2f(1.0, 1.0)
glVertex2f(this.width, this.height)
glTexCoord2f(0.0, 1.0)
glVertex2f(0.0, this.height)
glEnd()
输出二张图。
效果如下:
显示效果如我们所想,整体上变亮了。
第二个例子,我们传入一个数组,然后在GPU对每个数组加1。相应代码个性如下:
part = particle.gpgpubasic([11,12,13,14,15])
def InitGL(width,height):
glClearColor(0.1,0.1,0.5,0.1)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH)
#glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
camera.move(0.0,1.3,0.0)
camera.setthree(True)
camera.length = 3
global shaderall
shaderall = shaderProg.allshader()
global colorMap
global hightMap
colorMap = loadtexture.Texture.loadmap("ground2.bmp")
#hight map for cpu to gpu
hightMap = loadtexture.Texture.loadmap("hight.gif")
#create terrain use cpu
hightimage = loadtexture.Texture.loadterrain("hight.gif")
image = open("ground2.bmp").convert("RGBA")
plane.setHeight(hightimage)
#global part
#part = particle.gpgpubasic(image)
part.createFBO()
pingpong.createFBO()
part.renderFBO(shaderall.gpgpuProgram)
传入数组。
因为是混合在上文的代码中的,所以有一些多余代码,主要就是创建一个[112,128,132,141,152]的数组,然后把上文中相关传入图片的相关代码隐藏掉。原来着色器中增加vec4(0.2)改成vec4(1.0),并且在上文中的renderFBO添加如下代码:
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
glReadBuffer(GL_COLOR_ATTACHMENT0)
data = glReadPixels(0, 0, this.width, this.height,GL_RGBA,GL_FLOAT)
print "fbo data:",type(data),len(data),data[0],data[1]#,data[2]
glPopAttrib()
glBindFramebuffer(GL_FRAMEBUFFER,0)
#close fbo
glBindTexture(GL_TEXTURE_2D, 0)
glEnable(GL_DEPTH_TEST)
输出经过GPU更改后的数据。
显示效果:
根据前面的代码,可以看到,返回的数据长度还是5,前二个分量由112,128变成113,129了。
有了上面这些,我们已经知道如何把CPU的数据经过GPU处理后返回了,下面介绍一个在这基础之上的乒乓技术,是一个用来把渲染输出转换成为下一次运算的输入的技术,常见的如粒子系统里的运算如果放在GPU中,那么必需用乒乓技术来实现,因为GPU中数据是前次更新加上现在的结果。当然CPU中运算就简单了,直接每桢改变内存中的数据,然后更新VBO,VAO啥的就行了。
实现原理很简单,用FBO关联二个纹理,在第一渲染时,用第一个纹理数据经GPU处理后放入FBO关联的第二个纹理中,然后下一桢,把第二个纹理中的数据经过GPU处理放入第一个纹理。代码如下:
class gpgpupingpong(object):
def __init__(this,*args):
this.imageFormat = GL_FLOAT
this.index = 0
if len(args) == 1 :
if isinstance(args[0],Image):
image = args[0]
this.width = image.size[0]
this.height = image.size[1]
this.data = image.im
this.imageFormat = GL_UNSIGNED_BYTE
if isinstance(args[0],list):
listf = args[0]
this.width = len(listf) if len(listf) > 0 else 1
this.height = 1
this.data = listf
if len(args) == 3:
this.width = int(args[0])
this.height = int(args[1])
this.data = args[2]
this.imagedata = []
for i in range(this.height):
for j in range(this.width):
index = i * this.width + j
f4 = this.data[index] if index < len(this.data) else float(j) / float(this.width)
r,g,b,a = 0.0,0.0,0.0,0.0
if isinstance(f4,tuple):
if len(f4) == 2:
r,g = f4
elif len(f4) == 3:
r,g,b = f4
else:
r,g,b,a = f4
else:
r = f4
this.imagedata.append(r)
this.imagedata.append(g)
this.imagedata.append(b)
this.imagedata.append(a)
def createFBO(this):
this.fbo = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
#create texture for fbotext,GPU->CPU
this.fbotext = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D,this.fbotext)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this.width, this.height,0,GL_RGBA,GL_FLOAT,None)#GL_FLOAT
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
#relation fbo and fbotext(FBO and Texture2D)
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,this.fbotext,0) #glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,this.fbotext,0) #save data to texture.CPU->GPU
this.fbodata = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D,this.fbodata)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this.width, this.height, 0, GL_RGBA,GL_FLOAT,this.imagedata)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT1,GL_TEXTURE_2D,this.fbodata,0) glBindFramebuffer(GL_FRAMEBUFFER,0)
this.pingpong = [[GL_COLOR_ATTACHMENT0,this.fbodata],[GL_COLOR_ATTACHMENT1,this.fbotext]]
#cpu to gpu,and gpu compute result in fbo and fbotext.(cpu -(fbodata)> gpu
#-(fbotext)> cpu)
def renderFBO(this,shader):
ind = this.index % 2
this.index = this.index + 1
print "index",ind
pp = this.pingpong[ind]
glDisable(GL_DEPTH_TEST)
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
glDrawBuffer(pp[0])
glPushAttrib(GL_VIEWPORT_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0.0,this.width,0.0,this.height)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glViewport(0,0,this.width,this.height)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, pp[1])
glUseProgram(shader)
glUniform1i(shader.tex0, 0)
glUniform1f(shader.xl, this.width)
glUniform1f(shader.yl, this.height)
glBegin(GL_QUADS)
glVertex2f(0.0, 0.0)
glVertex2f(this.width, 0.0)
glVertex2f(this.width, this.height)
glVertex2f(0.0, this.height)
glEnd()
glUseProgram(0)
glBindFramebuffer(GL_FRAMEBUFFER,0)
if ind == 0 :
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT)
data = glReadPixels(0, 0, this.width, this.height,GL_RGBA,GL_FLOAT)
print "fbo 0:",len(data),data[0]#,data[1],data[2]
glBindFramebuffer(GL_FRAMEBUFFER,0)
else :
glBindFramebuffer(GL_FRAMEBUFFER,this.fbo)
glReadBuffer(GL_COLOR_ATTACHMENT1_EXT)
data = glReadPixels(0, 0, this.width, this.height,GL_RGBA,GL_FLOAT)
print "fbo 1:",len(data),data[0]#,data[1],data[2]
glBindFramebuffer(GL_FRAMEBUFFER,0) glPopAttrib()
#close fbo
glBindTexture(GL_TEXTURE_2D, 0)
glEnable(GL_DEPTH_TEST)
乒乓技术
整个过程和上面的差不多,但是需要注意的,在glBindFramebuffer后渲染前,需要指定输出到的FBO对应的绑定点,就是glDrawBuffer(pp[0])。
我们可以看下效果。传入pingpong = particle.gpgpupingpong([10,20,30]),然后每桢每顶点在GPU中加一。效果哪下(跑的有点快,只拿到加到200后的数据):
主要实践就到这个,因为上文中,顶点的着色器中处理不复杂,传入的顶点也不多,大家可能认为作用不大。但是大家如果想下,一张1000*1000像素的纹理,简单来算GPU只要能并行处理100个点,那也比CPU要高100倍。
今天这个特殊日子,祝大家马年吉祥,万事如意。
初试PyOpenGL三 (Python+OpenGL)GPGPU基本运算与乒乓技术的更多相关文章
- 初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞
这篇相当于是对前三篇的总结,基本效果如下: 在初试PyOpenGL一 (Python+OpenGL)讲解Pyopengl环境搭建,网格,球体,第一与第三人称摄像机的实现.在初试PyOpenGL二 (P ...
- 初试PyOpenGL一 (Python+OpenGL)
很早就一直想学Python,看到一些书都有介绍,不管是做为游戏的脚本语言,还是做为开发项目的主要语言都有提及(最主要的CUDA都开始支持Python,CUDA后面一定要学),做为先熟悉一下Python ...
- 初试PyOpenGL二 (Python+OpenGL)基本地形生成与高度检测
在上文中,讲述了PyOpenGL的基本配置,以及网格,球形的生成,以及基本的漫游.现在利用上一篇的内容,来利用高程图实现一个基本的地形,并且,利用上文中的第三人称漫游,以小球为视角,来在地形上前后左右 ...
- (Python OpenGL)【5】平移 PyOpenGL
(Python OpenGL) 原文:http://ogldev.atspace.co.uk/www/tutorial06/tutorial06.html (英文) 下面是我翻译过来的: 背景 在本 ...
- (Python OpenGL)【3】着色器 PyOpenGL
(Python OpenGL)现在开始我们使用着色器来进行渲染.着色器是目前做3D图形最流行的方式. OpenGL的渲染管线流程: 数据传输到OpenGL—>顶点处理器—>细分着色—> ...
- (Python OpenGL)【4】Uniform变量 PyOpenGL
(Python OpenGL) 原文:http://ogldev.atspace.co.uk/www/tutorial05/tutorial05.html(英文) __author__ = " ...
- 【Python OpenGL】【2】第一个三角形(Pyopengl)
根据顶点缓存来生成图元(Python OpenGL) 原文(英文链接)http://ogldev.atspace.co.uk/www/tutorial03/tutorial03.html __auth ...
- (Python OpenGL)【1】你好顶点 PyOpenGL
原文链接(C语言环境)(Python OpenGL) 我用python实现的代码: __author__ = "WSX" from OpenGL.GLUT.freeglut imp ...
- 三. Python基础(3)--语法
三. Python基础(3)--语法 1. 字符串格式化的知识补充 tpl = "我是%s,年龄%d,学习进度100%" %('Arroz',18) print(tpl) # 会提 ...
随机推荐
- 【Unity】第9章 粒子系统
分类:Unity.C#.VS2015 创建日期:2016-05-02 一.简介 粒子是在三维空间中渲染出来的二维图像,主要用于在场景中表现如烟.火.水滴.落叶.--等各种效果. Unity粒子系统 ( ...
- zabbix 实现对服务器的负载监控
# grep Include /etc/zabbix/zabbix_agentd.conf ### Option: Include # Include= Include=/etc/zabbix/zab ...
- android studio - 右键没有“New C++ Class 选项” 或 “Cannot find declaration to go to”的问题
今天在android studio的cpp文件夹上右键,发现竟然没有了New C++ Class“的选项,如下图所示: 上图是正常情况. 下图是非正常情况. 解决方案 检查”File“-"S ...
- angular学习笔记(三十)-指令(1)-概述
之前在 angular学习笔记(十九)-指令修改dom 里面已经简单的提到了angular中的指令,现在来详细的介绍 '指令' 一.指令的创建: dirAppModule.directive('dir ...
- DIOCP开源项目-DIOCP3的ECHO测试<贴图>
星期六开了测试台测试机子.星期天休息,今天早上来接两个图 开了2个客户端,一个qsl的echo client,一个是楠楠的dbiocp回调客户端.建立13240个连接 今天来后,机子很卡,后来发现是楠 ...
- [转]Unity3D新手引导开发手记
直接跳转吧 Unity3D新手引导开发手记 看到还不错就直接转过来了,我是有多懒啊
- 腾讯云主机安装登录mysql失败--解决方案[重置root密码并实现远程连接]
登录MySQL时报错:Access denied for user 'root'@'localhost' (using password: YES) 解决步骤: 1.使用ssh工具连接主机,使用mys ...
- Python给我的小伙伴来个微信机器人
[本文出自天外归云的博客园] 安装wxpy 首先你得去图灵机器人官网上注册个账号,登录后在机器人设置里面会有一个api_key,下文会用到! 然后说开发环境,我用的是python3环境,事先需要安装一 ...
- RTX基础教程目录
以下RTX教程转载自安富莱电子论坛: http://forum.armfly.com/forum.php?mod=viewthread&tid=16909&extra=page%3D1 ...
- Python爬虫技巧
Python爬虫技巧一之设置ADSL拨号服务器代理 reference: https://zhuanlan.zhihu.com/p/25286144 爬取数据时,是不是只能每个网站每个网站的分析,有没 ...