上篇讲述了一维FFT的GPU实现(FFT算法实现——基于GPU的基2快速傅里叶变换),后来我又由于需要做了一下二维FFT,大概思路如下。

首先看的肯定是公式:

如上面公式所描述的,2维FFT只需要拆分成行FFT,和列FFT就行了,其中我在下面的实现是假设原点在F(0,0),由于我的代码需要原点在中心,所以在最后我将原点移动到了中心。

下面是原点F(0,0)的2维FFT的伪代码:

  1. //C2DFFT
  2. //被执行2DFFT的是一个N*N的矩阵,在source_2d中按行顺序储存
  3. //水平方向FFT
  4. for (int i=;i<N;i++)
  5. {
  6. fft1(&source_2d[i*N],&source_2d_1[i*N],N);
  7. }
  8. //转置列成行
  9. for (int i=;i<N*N;i++)
  10. {
  11. int x = i%N;
  12. int y = i/N;
  13. int index = x*N+y;
  14. source_2d[index] = source_2d_1[i];
  15. }
  16. //垂直FFT
  17. for(int i=;i<N;i++)
  18. {
  19. fft1(&source_2d[i*N],&source_2d_1[i*N],N);
  20. }
  21. //转置回来
  22. for (int i=;i<N*N;i++)
  23. {
  24. int x = i%N;
  25. int y = i/N;
  26. int index = x*N+y;
  27. source_2d[index] = source_2d_1[i];
  28. }

GPU实现无非把这些东西转换到GPU上。

我基于OpenGL的fragment shader来计算fft;数据都存放在纹理或者FBO里面。和1维fft不同的是,NXN的数据里面,只是对当前列或者当前排做一维FFT,所以bit反转表只需要一个1*N的buffer就可以了。对应的蝴蝶图数据也只需要1*N即可。所以我们有如下的分配:

  1. static ofFbo _fbo_bitrev_table;
  2. static ofFbo _origin_butterfly_2d;
  3.  
  4. _fbo_bitrev_table.allocate(N,,GL_RGBA32F);
  5. _origin_butterfly_2d.allocate(N,,GL_RGBA32F);

首先要做的是把长度为N的bit反转表求出来,这个只需要求一次,所以在最开始的时候就用CPU求出来:

  1. for(int i=;i<N;i++)
  2. {
  3. _bitrev_index_2d.setColor(i,,ofFloatColor(bit_rev(i,N-),,,));
  4. }
  5.  
  6. _bitrev_index_2d.update();
  7.  
  8. //翻转后的索引
  9. _fbo_bitrev_table.begin();
  10. _bitrev_index_2d.draw(,,N,);
  11. _fbo_bitrev_table.end();

然后初始化最初的蝴蝶图,这个和1维FFT是一样的,只是长度不同而已:

  1. for(int i=;i<N;i++)
  2. {
  3. //初始化二维蝴蝶图
  4. if(i%==)
  5. {
  6. _data_2d.setColor(i,,ofFloatColor(.f,.f,,i+));
  7. }
  8. else
  9. {
  10. _data_2d.setColor(i,,ofFloatColor(.f,.f,,i-));
  11. }
  12.  
  13. }
  14.  
  15. _data_2d.update();
  16.  
  17. /////////////////2D初始化/////////////////
  18. //初始化2D蝴蝶图
  19. _weight_index_2d[].begin();
  20. _data_2d.draw(,,N,);
  21. _weight_index_2d[].end();
  22. //备份2D初始蝴蝶图,用于下一次新的计算
  23. _origin_butterfly_2d.begin();
  24. _data_2d.draw(,,N,);
  25. _origin_butterfly_2d.end();

辅助函数:

  1. static unsigned int bit_rev(unsigned int v, unsigned int maxv)
  2. {
  3. unsigned int t = log(maxv + )/log();
  4. unsigned int ret = ;
  5. unsigned int s = 0x80000000>>();
  6. for (unsigned int i = ; i < t; ++i)
  7. {
  8. unsigned int r = v&(s << i);
  9. ret |= (r << (t-i-)) >> (i);
  10. }
  11. return ret;
  12. }
  13.  
  14. static void bit_reverse_copy(RBVector2 src[], RBVector2 des[], int len)
  15. {
  16. for (int i = ; i < len;i++)
  17. {
  18. des[bit_rev(i, len-)] = src[i];
  19. }
  20. }

下面定义计算2维IFFT的函数:

  1. void GPUFFT::ifft_2d(ofFbo& in,ofFbo& out,int size);

其中in是输入,out是输出,size就是N,由初始化的时候传入了一次,在这里写是为了方便调试的时候临时改变尺寸。

Ifft本身的代码和上面形式一样,内容变成了各种shader计算:

  1. void GPUFFT::ifft_2d(ofFbo& in,ofFbo& out,int size)
  2. {
  3. //禁用Alpha混合,否则绘制到FBO会混合Alpha,造成数据丢失
  4. ofDisableAlphaBlending();
  5.  
  6. //水平FFT
  7. _weight_index_2d[_cur_2d].begin();
  8. _origin_butterfly_2d.draw(,,N,);
  9. _weight_index_2d[_cur_2d].end();
  10.  
  11. _fbo_in_bitreved_2d.begin();
  12. _bit_reverse_shader_2d.begin();
  13. _bit_reverse_shader_2d.setUniform3f("iResolution",N,N,);
  14. _bit_reverse_shader_2d.setUniform1i("N",N);
  15. _bit_reverse_shader_2d.setUniform1i("dir",);
  16. _bit_reverse_shader_2d.setUniformTexture("tex_origin",in.getTextureReference(),);
  17. _bit_reverse_shader_2d.setUniformTexture("tex_bitreverse_table",_fbo_bitrev_table.getTextureReference(),);
  18. ofRect(,,N,N);
  19. _bit_reverse_shader_2d.end();
  20. _fbo_in_bitreved_2d.end();
  21.  
  22. //翻转后的数据
  23. _res_back_2d[_cur_2d].begin();
  24. _fbo_in_bitreved_2d.draw(,,N,N);
  25. _res_back_2d[_cur_2d].end();
  26.  
  27. for(int i = ;i<N;i*=)
  28. {
  29. _res_back_2d[-_cur_2d].begin();
  30. ofClear(,,,);
  31. _gpu_fft_shader_2d.begin();
  32. _gpu_fft_shader_2d.setUniform1i("size",N);
  33. _gpu_fft_shader_2d.setUniform1i("n_step",i);
  34. _gpu_fft_shader_2d.setUniform3f("iResolution",N,N,);
  35. _gpu_fft_shader_2d.setUniform1i("dir",);
  36. _gpu_fft_shader_2d.setUniformTexture("tex_index_weight",_weight_index_2d[_cur_2d].getTextureReference(),);
  37. _gpu_fft_shader_2d.setUniformTexture("tex_res_back",_res_back_2d[_cur_2d].getTextureReference(),);
  38. //_gpu_fft_shader_2d.setUniformTexture("test",imag_test.getTextureReference(),4);
  39.  
  40. ofRect(,,N,N);
  41.  
  42. _gpu_fft_shader_2d.end();
  43.  
  44. _res_back_2d[-_cur_2d].end();
  45.  
  46. _weight_index_2d[-_cur_2d].begin();
  47. ofClear(,,,);
  48.  
  49. _weight_index_shader_2d.begin();
  50. _weight_index_shader_2d.setUniform1i("size",N);
  51. _weight_index_shader_2d.setUniform1i("n_step",i);
  52. _weight_index_shader_2d.setUniform3f("iResolution",N,,);
  53. _weight_index_shader_2d.setUniform1i("dir",);
  54. _weight_index_shader_2d.setUniformTexture("tex_input",_weight_index_2d[_cur_2d].getTextureReference(),);
  55.  
  56. ofRect(,,N,);
  57.  
  58. _weight_index_shader_2d.end();
  59.  
  60. _weight_index_2d[-_cur_2d].end();
  61.  
  62. _cur_2d = - _cur_2d;
  63. }
  64.  
  65. //for ifft
  66. _res_back_2d[-_cur_2d].begin();
  67. _res_back_2d[_cur_2d].draw(,,N,N);
  68. _res_back_2d[-_cur_2d].end();
  69.  
  70. _res_back_2d[_cur_2d].begin();
  71. _ifft_div_shader_2d.begin();
  72. _ifft_div_shader_2d.setUniform1i("N",N);
  73. _ifft_div_shader_2d.setUniform3f("iResolution",N,N,);
  74. _ifft_div_shader_2d.setUniformTexture("tex_rgb",_res_back_2d[-_cur_2d].getTextureReference(),);
  75. ofRect(,,N,N);
  76. _ifft_div_shader_2d.end();
  77. _res_back_2d[_cur_2d].end();
  78.  
  79. //垂直FFT
  80. //垂直方向的所有都是计算都按照垂直方向来
  81. _weight_index_2d[_cur_2d].begin();
  82. _origin_butterfly_2d.draw(,,N,);
  83. _weight_index_2d[_cur_2d].end();
  84.  
  85. //这一步不会将垂直水平化
  86. _fbo_in_bitreved_2d.begin();
  87. _bit_reverse_shader_2d.begin();
  88. _bit_reverse_shader_2d.setUniform3f("iResolution",N,N,);
  89. _bit_reverse_shader_2d.setUniform1i("N",N);
  90. _bit_reverse_shader_2d.setUniform1i("dir",);
  91. _bit_reverse_shader_2d.setUniformTexture("tex_origin",_res_back_2d[_cur_2d].getTextureReference(),);
  92. _bit_reverse_shader_2d.setUniformTexture("tex_bitreverse_table",_fbo_bitrev_table.getTextureReference(),);
  93. ofRect(,,N,N);
  94. _bit_reverse_shader_2d.end();
  95. _fbo_in_bitreved_2d.end();
  96.  
  97. //翻转后的数据
  98. _res_back_2d[_cur_2d].begin();
  99. _fbo_in_bitreved_2d.draw(,,N,N);
  100. _res_back_2d[_cur_2d].end();
  101.  
  102. for(int i = ;i<N;i*=)
  103. {
  104. _res_back_2d[-_cur_2d].begin();
  105. ofClear(,,,);
  106. _gpu_fft_shader_2d.begin();
  107. _gpu_fft_shader_2d.setUniform1i("size",N);
  108. _gpu_fft_shader_2d.setUniform1i("n_step",i);
  109. _gpu_fft_shader_2d.setUniform3f("iResolution",N,N,);
  110. _gpu_fft_shader_2d.setUniform1i("dir",);
  111. _gpu_fft_shader_2d.setUniformTexture("tex_index_weight",_weight_index_2d[_cur_2d].getTextureReference(),);
  112. _gpu_fft_shader_2d.setUniformTexture("tex_res_back",_res_back_2d[_cur_2d].getTextureReference(),);
  113. //_gpu_fft_shader_2d.setUniformTexture("test",imag_test.getTextureReference(),4);
  114.  
  115. ofRect(,,N,N);
  116.  
  117. _gpu_fft_shader_2d.end();
  118.  
  119. _res_back_2d[-_cur_2d].end();
  120.  
  121. _weight_index_2d[-_cur_2d].begin();
  122. ofClear(,,,);
  123.  
  124. _weight_index_shader_2d.begin();
  125. _weight_index_shader_2d.setUniform1i("size",N);
  126. _weight_index_shader_2d.setUniform1i("n_step",i);
  127. _weight_index_shader_2d.setUniform3f("iResolution",N,,);
  128. _weight_index_shader_2d.setUniform1i("dir",);
  129. _weight_index_shader_2d.setUniformTexture("tex_input",_weight_index_2d[_cur_2d].getTextureReference(),);
  130.  
  131. ofRect(,,N,);
  132.  
  133. _weight_index_shader_2d.end();
  134.  
  135. _weight_index_2d[-_cur_2d].end();
  136.  
  137. _cur_2d = - _cur_2d;
  138. }
  139.  
  140. //for ifft
  141. _res_back_2d[-_cur_2d].begin();
  142. _res_back_2d[_cur_2d].draw(,,N,N);
  143. _res_back_2d[-_cur_2d].end();
  144.  
  145. _res_back_2d[_cur_2d].begin();
  146. _ifft_div_shader_2d.begin();
  147. _ifft_div_shader_2d.setUniform1i("N",N);
  148. _ifft_div_shader_2d.setUniform3f("iResolution",N,N,);
  149. _ifft_div_shader_2d.setUniformTexture("tex_rgb",_res_back_2d[-_cur_2d].getTextureReference(),);
  150. ofRect(,,N,N);
  151. _ifft_div_shader_2d.end();
  152. _res_back_2d[_cur_2d].end();
  153.  
  154. out.begin();
  155. _res_back_2d[_cur_2d].draw(,,N,N);
  156. out.end();
  157.  
  158. //恢复Alpha混合
  159. //ofEnableAlphaBlending();
  160. }

现在来看shader内容:

_bit_reverse_shader_2d

这个shader用于将整个N*N的数据全部按照行或者按照列进行翻装,使之满足执行fft的条件:

  1. #version
  2. uniform sampler2D tex_origin;
  3. //1xN查找表,用于查找索引对应的bitreverse数
  4. uniform sampler2D tex_bitreverse_table;
  5. //1 for x direction,2 for y direction
  6. uniform int dir;
  7. uniform int N;
  8. uniform vec3 iResolution;
  9.  
  10. out vec4 outColor;
  11.  
  12. void main()
  13. {
  14. vec2 tex_coord = gl_FragCoord.xy/iResolution.xy;
  15.  
  16. vec2 table_index;
  17. table_index.y = 0.5;
  18. if(dir==)
  19. table_index.x = tex_coord.x;
  20. else
  21. table_index.x = tex_coord.y;
  22. float bitreverse = texture(tex_bitreverse_table,table_index).r;
  23.  
  24. vec2 origin_index;
  25. if(dir==)
  26. {
  27. //x方向
  28. origin_index.y = tex_coord.y;
  29. origin_index.x = (bitreverse+0.5)/N;
  30. }
  31. else
  32. {
  33. //y方向
  34. origin_index.x = tex_coord.x;
  35. origin_index.y = (bitreverse+0.5)/N;
  36. }
  37. vec2 param = texture(tex_origin,origin_index).xy;
  38.  
  39. outColor = vec4(param,,);
  40. }

_gpu_fft_shader_2d

这是fft执行计算的部分,同样分为按行和按列:

  1. #version
  2. //NX1
  3. uniform sampler2D tex_index_weight;
  4. //NXN
  5. uniform sampler2D tex_res_back;
  6. uniform sampler2D test;
  7. uniform int size;
  8. uniform int n_step;
  9. //1 for x direction,2 for y direction
  10. uniform int dir;
  11.  
  12. uniform vec3 iResolution;
  13.  
  14. out vec4 outColor;
  15.  
  16. void main()
  17. {
  18. vec2 tex_coord = gl_FragCoord.xy/iResolution.xy;
  19.  
  20. vec2 first_index;
  21. if(dir==)
  22. {
  23. first_index.y = 0.5;
  24. first_index.x = tex_coord.x;
  25. }
  26. else
  27. {
  28. first_index.y = 0.5;
  29. first_index.x = tex_coord.y;
  30. }
  31.  
  32. float cur_x = gl_FragCoord.x - 0.5;
  33. float cur_y = gl_FragCoord.y - 0.5;
  34.  
  35. vec2 outv;
  36.  
  37. vec4 temp = texture(tex_index_weight,first_index);
  38. //ifft
  39. vec2 weight = vec2(cos(temp.r/temp.g**3.141592653),-sin(temp.r/temp.g**3.141592653));
  40. //fft
  41. //vec2 weight = vec2(cos(temp.r/temp.g*2*3.141592653),sin(temp.r/temp.g*2*3.141592653));
  42. vec2 _param2_index;
  43.  
  44. if(dir==)
  45. {
  46. _param2_index.x = (temp.a + 0.5)/size;
  47. _param2_index.y = tex_coord.y;
  48. }
  49. else
  50. {
  51. _param2_index.x = tex_coord.x;
  52. _param2_index.y = (temp.a + 0.5)/size;
  53. }
  54.  
  55. vec2 param1 = texture(tex_res_back,tex_coord).rg;
  56. vec2 param2 = texture(tex_res_back,_param2_index).rg;
  57.  
  58. float tex_coord_n1;
  59. float tex_coord_n2;
  60. if(dir==)
  61. {
  62. tex_coord_n1 = cur_x;
  63. }
  64. else
  65. {
  66. tex_coord_n1 = cur_y;
  67. }
  68.  
  69. tex_coord_n2 = temp.a;
  70.  
  71. if(tex_coord_n1<tex_coord_n2)
  72. {
  73. outv.r = param1.r + param2.r*weight.r-weight.g*param2.g;
  74. outv.g = param1.g +weight.r*param2.g + weight.g*param2.r;
  75. }
  76. else
  77. {
  78. outv.r = param2.r + param1.r*weight.r-weight.g*param1.g;
  79. outv.g = param2.g +weight.r*param1.g + weight.g*param1.r;
  80. }
  81.  
  82. outColor = vec4(outv,,);
  83.  
  84. }

_weight_index_shader_2d

更新蝴蝶图索引:

  1. #version
  2.  
  3. uniform sampler2D tex_input;
  4. uniform int size;
  5. uniform int n_total;
  6. //start with 2
  7. uniform int n_step;
  8. //1 for x direction,2 for y direction
  9. uniform int dir;
  10.  
  11. uniform vec3 iResolution;
  12. out vec4 outColor;
  13.  
  14. void main()
  15. {
  16. vec2 tex_coord = gl_FragCoord.xy/iResolution.xy;
  17. vec4 fetch = texture(tex_input,tex_coord);
  18. float cur_x = gl_FragCoord.x - 0.5;
  19. float cur_y = gl_FragCoord.y - 0.5;
  20.  
  21. vec4 outv;
  22. float tex_coord_n;
  23. if(dir==)
  24. {
  25. //x dir
  26. tex_coord_n = cur_x;
  27. }
  28. else
  29. {
  30. //y dir
  31. tex_coord_n = cur_x;
  32. }
  33.  
  34. //updata weight
  35. vec2 pre_w = fetch.rg;
  36. float i = pre_w.r;
  37. float n = pre_w.g;
  38. float new_i;
  39. float new_n;
  40. new_i = i;
  41. new_n = n*;
  42. if(int(tex_coord_n)%(n_step*) > n_step*-)
  43. {
  44. new_i += n_step*;
  45. }
  46. outv.r = new_i;
  47. outv.g = new_n;
  48. //outv.rg = tex_coord;
  49.  
  50. //updata index
  51. vec2 pre_index = fetch.ba;
  52. int x = int(pre_index.x);
  53. int y = int(pre_index.y);
  54. int ni = n_step*;
  55. float new_tex_coord_n = tex_coord_n;
  56. if((int(tex_coord_n)/ni)%==)
  57. {
  58. new_tex_coord_n += ni;
  59. }
  60. else
  61. {
  62. new_tex_coord_n -= ni;
  63. }
  64.  
  65. outv.b = ;
  66. outv.a = new_tex_coord_n;
  67. outColor = outv;
  68. //outColor = vec4(tex_coord_n,tex_coord_n%n_step,tex_coord_n%n_step,tex_coord_n%n_step);
  69. }

最后的

_ifft_div_shader_2d

是为了计算ifft,将每个计算结果除以一个N:

  1. #version
  2. uniform sampler2D tex_rgb;
  3. uniform int N;
  4. uniform vec3 iResolution;
  5.  
  6. out vec4 outColor;
  7.  
  8. void main()
  9. {
  10. vec2 tex_coord = gl_FragCoord.xy/iResolution.xy;
  11.  
  12. vec2 outv;
  13.  
  14. vec4 c = texture(tex_rgb,tex_coord);
  15.  
  16. outv.r = c.r/N;
  17. outv.g = c.g/N;
  18. outColor = vec4(outv,,);
  19. }

最后,out里面就是结果了。

对于将原点移动到中心多了以下shader:

  1. vec4 c;
  2. if(tex_coord.x>0.5&&tex_coord.y>0.5)
  3. {
  4. c = texture(tex_rgb,tex_coord-vec2(0.5,0.5));
  5.  
  6. }
  7. if(tex_coord.x>0.5&&tex_coord.y<0.5)
  8. {
  9. c = texture(tex_rgb,tex_coord+vec2(-0.5,0.5));
  10. }
  11. if(tex_coord.x<0.5&&tex_coord.y>0.5)
  12. {
  13. c = texture(tex_rgb,tex_coord+vec2(0.5,-0.5));
  14. }
  15. if(tex_coord.x<0.5&&tex_coord.y<0.5)
  16. {
  17. c = texture(tex_rgb,tex_coord+vec2(0.5,0.5));
  18. }
  19. outColor = c;

2维FFT算法实现——基于GPU的基2快速二维傅里叶变换的更多相关文章

  1. FFT算法实现——基于GPU的基2快速傅里叶变换

    最近做一个东西,要用到快速傅里叶变换,抱着蛋疼的心态,自己尝试写了一下,遇到一些问题. 首先看一下什么叫做快速傅里叶变换(FFT)(来自Wiki): 快速傅里叶变换(英语:Fast Fourier T ...

  2. JAVA描述算法和数据结构(01):稀疏数组和二维数组转换

    本文源码:GitHub·点这里 || GitEE·点这里 一.基本简介 1.基础概念 在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵:与之相反, ...

  3. 功能要求:定义一个两行三列的二维数组 names 并赋值,使用二重循环输出二维数组中的元素。

    功能要求:定义一个两行三列的二维数组 names 并赋值,使用二重循环输出二维数组中的元素 names={{"tom","jack","mike&qu ...

  4. 【算法系列学习】codeforces D. Mike and distribution 二维贪心

    http://codeforces.com/contest/798/problem/D http://blog.csdn.net/yasola/article/details/70477816 对于二 ...

  5. Android二维码开源项目zxing用例简化和生成二维码、条形码

    上一篇讲到:Android二维码开源项目zxing编译,编译出来后有一个自带的測试程序:CaptureActivity比較复杂,我仅仅要是把一些不用的东西去掉,用看起来更方便,二维码和条形码的流行性自 ...

  6. 今天网站后台登录页面需要生成一个二维码,然后在手机app上扫描这个二维码,实现网站登录的效果及其解决方案如下

    要实现二维码登录,需要解决2个技术,1.需要js websocket 与后台php实现长连接技术 2.实现二维码生成技术 要实现这个功能第二个算是比较简单,只需要下载一个php的二维码生成器即可,但要 ...

  7. 微信生成二维码 只需一个网址即刻 还有jquery生成二维码

    <div class="orderDetails-info"> <img src="http://qr.topscan.com/api.php?text ...

  8. 二维码解析:使用 JavaScript 库reqrcode.js解析二维码

    上次使用QRCode.js可以来生成二维码,但是我没有找到有文档说明可以对存在的二维码进行扫描解析其中的内容. 幸亏查找到了可行的解决方案,而且很好使哦!就是reqrcode.js 地址:https: ...

  9. 二维码生成:使用 JavaScript 库QRCode.js生成二维码

    QRCode.js:跨浏览器的javascript二维码生成库,支持html5的Canvas画布,没有任何依赖. Github 地址:https://github.com/davidshimjs/qr ...

随机推荐

  1. Robot Framework常用关键字介绍

    常用关键字介绍 在学习一门编程语言的时候,大多教材都是从打印“hello world”开始.我们可以像编程语言一样来学习 Robot Framework.虽然通过 RIDE 提供“填表”一样的写测试用 ...

  2. 9、在Shell脚本中调用其他脚本

    在Shell脚本的执行过程中,Shell脚本支持调用另一个Shell脚本,调用的格式为:程序名 实例:在Shell脚本test1中调用test2. 1.调用test2#test1脚本root@ubun ...

  3. bzoj 5252: [2018多省省队联测]林克卡特树

    Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做& ...

  4. zIndex 属性设置元素的堆叠顺序。

    http://www.w3school.com.cn/jsref/prop_style_zindex.asp zIndex 属性设置元素的堆叠顺序. 该属性设置一个定位元素沿 z 轴的位置,z 轴定义 ...

  5. jquery 闭包

    jQuery 闭包结构 1 2 3 4 5 6 7 // 用一个函数域包起来,就是所谓的沙箱 // 在这里边 var 定义的变量,属于这个函数域内的局部变量,避免污染全局 // 把当前沙箱需要的外部变 ...

  6. 记一次java程序内存溢出问题

    一个自然语言处理程序,在封装为web-service后,部署到线上运行. 但最近出现了内存溢出的情况,频繁的out of memory. 先盲目尝试在启动脚本中增加-XX:-UseGCOverhead ...

  7. CXF - JAX-WS入门

    相关dependency,我使用的版本是2.7.11: <dependency> <groupId>org.apache.cxf</groupId> <art ...

  8. MySQL 里的 Timestrap 和 DateTime 和 Java 中的 Date

    世界标准时(UTC) 和 格林威治标准时(GMT) 怎么样的时间算是准确的呢?例如这一分种内是60s ,而下一分钟实际走到了59秒的时候却显示一分钟到了,即是时间快了,这样定义为不准确.下面两个解释可 ...

  9. 关于asp.net假分页的删除操作的随笔

    作为一个新人,上周负责优化一个后台管理系统,遇到一个问题:点击删除按钮之后,页面又回到了第一页. 而我需要达到的效果是:点击了删除按钮之后,原来是那一页,删除后还是在那一页. 由于项目是已经验收了的, ...

  10. javascript bind在回调中精简匿名函数的用法

    常规写法: Promise对象回调,匿名函数调用其他方法 更精简的写法: 注:这种写法的使用有两个严苛的限制. 1.回调的结果必须放在实际调用方法参数的最后一位: 2.回调函数中只调用其他一个方法.