OpenMP 环境变量使用总结

OpenMP 环境变量使用总结

  • OMP_CANCELLATION,在 OpenMP 规范 4.5 当中规定了取消机制,我们可以使用这个环境变量去设置是否启动取消机制,如果这个值等于 TRUE 那么就是开启线程取消机制,如果这个值等于 FALSE 那么就是关闭取消机制。
#include <stdio.h>
#include <omp.h>

int main()
{

   int s = omp_get_cancellation();
   printf("%d\n", s);
#pragma omp parallel num_threads(8) default(none)
   {
      if (omp_get_thread_num() == 2)
      {
#pragma omp cancel parallel
      }

      printf("tid = %d\n", omp_get_thread_num());

   }
   return 0;
}

在上面的程序当中,如果我们启动取消机制,那么线程号等于 2 的线程就不会执行后面的 printf 语句。

➜  cmake-build-hun git:(master) ✗  export OMP_CANCELLATION=TRUE # 启动取消机制
➜  cmake-build-hun git:(master) ✗ ./cancel 
1
tid = 0
tid = 4
tid = 1
tid = 3
tid = 5
tid = 6
tid = 7
  • OMP_DISPLAY_ENV,这个环境变量的作用就是程序在执行的时候首先会打印 OpenMP 相关的环境变量。如果这个环境变量值等于 TRUE 就会打印环境变量的值,如果是 FLASE 就不会打印。
➜  cmake-build-hun git:(master) ✗ export OMP_DISPLAY_ENV=TRUE   
➜  cmake-build-hun git:(master) ✗ ./critical 

OPENMP DISPLAY ENVIRONMENT BEGIN
  _OPENMP = '201511'
  OMP_DYNAMIC = 'FALSE'
  OMP_NESTED = 'FALSE'
  OMP_NUM_THREADS = '32'
  OMP_SCHEDULE = 'DYNAMIC'
  OMP_PROC_BIND = 'FALSE'
  OMP_PLACES = ''
  OMP_STACKSIZE = '0'
  OMP_WAIT_POLICY = 'PASSIVE'
  OMP_THREAD_LIMIT = '4294967295'
  OMP_MAX_ACTIVE_LEVELS = '2147483647'
  OMP_CANCELLATION = 'TRUE'
  OMP_DEFAULT_DEVICE = '0'
  OMP_MAX_TASK_PRIORITY = '0'
  OMP_DISPLAY_AFFINITY = 'FALSE'
  OMP_AFFINITY_FORMAT = 'level %L thread %i affinity %A'
OPENMP DISPLAY ENVIRONMENT END
data = 0
  • OMP_DYNAMIC,如果将这个环境变量设置为true,OpenMP实现可以调整用于执行并行区域的线程数,以优化系统资源的使用。与这个环境变量相关的一共有两个函数:
void omp_set_dynamic(int);
int omp_get_dynamic(void);

omp_set_dynamic 使用这个函数表示是否设置动态调整线程的个数,如果传入的参数不等于 0 表示开始,如果参数等于 0 就表示关闭动态调整。

我们现在来谈一谈 dynamic 动态调整线程个数以优化系统资源的使用是什么意思,这个意思就是 OpenMP 创建的线程个数在同一个时刻不会超过你系统的处理器的个数,因为 OpenMP 常常用在数据密集型任务当中,这类任务对 CPU 的需求大,因此为了充分利用资源,只会创建处理器个数的线程个数。

下面我们使用一个例子来验证上面所谈到的内容。

#include <omp.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
//   omp_set_dynamic(1);

#pragma omp parallel num_threads(33) default(none)
   {
      printf("tid = %d\n", omp_get_thread_num());
   }

   return 0;
}

上面的代码如果我们没有设置 OMP_DYNAMIC=TRUE 或者没有使用 omp_set_dynamic(1) 去启动态调整的话,那么上面的 printf 语句会被执行 33 次,但是如果你进行了设置,也就是启动了动态调整线程的个数的话,那么创建的线程个数就是 min(33, num_processors) ,后者是你的机器的处理器的个数,比如如果处理器的核的个数是 16 那么就只会有 16 个线程执行并行域当中的代码。

  • OMP_NESTED,这个表示是否开启并行域的嵌套模式,这个环境变量要么是 TRUE 或者 FALSE ,如果这个环境变量的值为 TRUE 那么能够嵌套的最大的并行域的数量受到环境变量 OMP_MAX_ACTIVE_LEVELS 的限制,与这个环境变量相关的一个动态库函数为 void omp_set_nested(int nested); ,表示是否开启嵌套的并行域。
  • OMP_NUM_THREADS,这个表示设置并行域的线程个数,与这个环境变量相关的有 num_threads 这个子句和动态库函数 void omp_set_num_threads(int num_threads);也是相关的。他们的优先级为:num_threads > omp_set_num_threads > OMP_NUM_THREADS。这个环境变量的值必须是一个大于 0 的整数,关于他们的优先级你可以认为离并行域越远的就优先级越低,反之越高。
  • OMP_STACKSIZE,这个环境变量的主要作用就是设置一个线程的栈空间的大小。
  • OMP_WAIT_POLICY,这个参数的主要作用就是控制当线程没有拿到锁的时候是自旋获取锁还是进入内核被挂起。这个参数主要有两个值,active 或者 passive。
    • PASSIVE,等待的线程不消耗 CPU ,而是进入内核挂起。
    • ACTIVE,等待的线程消耗 CPU,一直自旋获取锁。

我们现在使用例子来验证上面的规则:

#include <stdio.h>
#include <omp.h>

int main()
{
   omp_lock_t lock;
   omp_init_lock(&lock);
#pragma omp parallel num_threads(16) default(none) shared(lock)
   {
      omp_set_lock(&lock);
      while (1);
      omp_unset_lock(&lock);
   }
   return 0;
}

在上面的代码当中有一个并行域,并行域中线程的个数是 16,我们首先使用 ACTIVE 来看一下这个进程的负载,根据前面我们的描述那么 16 个线程都会在自旋获取锁,这个过程将会一直使用 CPU,因此这个进程的负载 %CPU ,应该是接近 1600 % ,每个线程都是 100% 加起来就是 1600 % 。

➜  cmake-build-openmp export OMP_WAIT_POLICY=ACTIVE 
➜  cmake-build-openmp ./wait_policy                

我们使用 top 命令查看一下这个进程的 CPU 使用率。

top - 17:27:14 up 263 days,  2:11,  2 users,  load average: 93.87, 87.59, 85.78
Tasks:  31 total,   2 running,  29 sleeping,   0 stopped,   0 zombie
%Cpu(s): 80.0 us,  0.7 sy,  0.0 ni, 19.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 13191648+total, 54673112 free, 15049648 used, 62193724 buff/cache
KiB Swap: 12499968+total, 11869649+free,  6303184 used. 11600438+avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
112290 root      20   0  133868   1576   1452 R  1600  0.0  11:52.84 wait_policy

根据上面的输出结果我们可以看到我们的预测是对的,所有的线程都活跃的在使用 CPU。

现在我们再来看一下如果我们使用 PASSIVE 的情况会是怎么样的?根据前面的描述如果线程没有获取到锁那么就会被挂起,因为只能够有一个线程获取到锁,其余 15 个线程都将被挂起,因此 CPU 的使用率应该是 100 % 左右,这个线程就是那个获取到锁的线程。

➜  cmake-build-openmp export OMP_WAIT_POLICY=PASSIVE
➜  cmake-build-openmp ./wait_policy 

我们再使用 top 命令查看一下对应的输出:

top - 17:27:53 up 263 days,  2:11,  2 users,  load average: 92.76, 88.10, 86.03
Tasks:  31 total,   2 running,  29 sleeping,   0 stopped,   0 zombie
%Cpu(s): 53.3 us,  0.8 sy,  0.0 ni, 45.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 13191648+total, 54675824 free, 15046932 used, 62193728 buff/cache
KiB Swap: 12499968+total, 11869649+free,  6303184 used. 11600710+avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
112317 root      20   0  133868   1624   1496 R  99.3  0.0   0:04.58 wait_policy

从上面的输出结果来看也是符合我们的预期,只有一个线程在不断的使用 CPU。

  • GOMP_SPINCOUNT,这个环境变量的主要作用就是当 OMP_WAIT_POLICY 是 active 的时候,最多忙等待自旋多少次,如果自旋的次数超过这个值的话,那么这个线程将会被挂起。

    当这个环境变量没有定义:

    • OMP_WAIT_POLICY=PASSIVE,那么自旋次数为 0 。
    • 如果 OMP_WAIT_POLICY 也是未定义的话,那么这个自旋次数将会被设置成 300,000 。
    • OMP_WAIT_POLICY=ACTIVE,那么自旋的次数是 300 亿次。

    另外如果 OpenMP 的线程的个数大于可用的 CPU 的核心的个数的时候,1000 和 100 次就是 GOMP_SPINCOUNT 的值,对应OMP_WAIT_POLICY=ACTIVE 和 OMP_WAIT_POLICY 没有定义。

  • OMP_MAX_TASK_PRIORITY,这个是设置 OpenMP 任务的优先级的最大值,这个值应该是一个大于等于 0 的值,如果没有定义,默认优先级的值就是 0 。

  • OMP_MAX_ACTIVE_LEVELS,这个参数的主要作用是设置最大的嵌套的并行域的个数。

  • GOMP_CPU_AFFINITY,这个环境变量的作用就是将线程绑定到特定的 CPU 核心上。该变量应包含以空格分隔或逗号分隔的CPU列表。此列表可能包含不同类型的条目:任意顺序的单个CPU编号、CPU范围(M-N)或具有一定步长的范围(M-N:S)。CPU编号从零开始。例如,GOMP_CPU_AFFINITY=“0 3 1-2 4-15:2”将分别将初始线程绑定到CPU 0,第二个绑定到CPU 3,第三个绑定到CPU1,第四个绑定到CPU 2,第五个绑定到CPU 4,第六个到第十个绑定到ccu 6、8、10、12和14,然后从列表的开头开始重新分配。GOMP_CPU_AFFINITY=0将所有线程绑定到CPU 0。

我们现在来使用一个例子查看环境变量的使用。我们的测试程序如下:

#include <stdio.h>
#include <omp.h>

int main()
{
   omp_lock_t lock;
   omp_init_lock(&lock);
#pragma omp parallel num_threads(4) default(none) shared(lock)
   {
      while (1);
   }
   return 0;
}

上面的程序就是开启四个线程然后进行死循环。在我的测试环境中一共有 4 个 CPU 计算核心。我们现在执行上面的程序,对应的结果如下所示,下面的图是使用命令 htop 得到的结果:

➜  tmp ./a.out
────────────────────────────────────────────────────────────────────────────────

    0[||||||||||||||||||||||||100.0%]   Tasks: 118, 212 thr; 4 running
    1[||||||||||||||||||||||||100.0%]   Load average: 2.62 0.86 0.29
    2[||||||||||||||||||||||||100.0%]   Uptime: 04:21:10
    3[||||||||||||||||||||||||100.0%]
  Mem[||||||||||||||||||||575M/3.82G]
  Swp[                      0K/3.82G]

    PID USER      PRI  NI  VIRT   RES   SHR S CPU%▽MEM%   TIME+  Command
  10750 lehung     20   0 27304   852   756 R 400.  0.0  2:30.53 ./a.out

从上面 htop 命令的输出结果可以看到 0 - 3 四个核心都跑满了,我们现在来看一下如果我们使用 GOMP_CPU_AFFINITY 环境变量使用线程绑定的方式 CPU 的负载将会是什么样!下面我们将所有的线程绑定到 0 1 两个核心,那么根据我们之前的分析 0 号核心上将会有第一个和第三个线程,1 号核心将会有第二个和第四个线程在上面运行。

➜  tmp export GOMP_CPU_AFFINITY="0 1"
➜  tmp ./a.out
────────────────────────────────────────────────────────────────────────────────

    0[||||||||||||||||||||||||100.0%]   Tasks: 118, 213 thr; 4 running
    1[||||||||||||||||||||||||100.0%]   Load average: 2.29 1.10 0.41
    2[|                         1.3%]   Uptime: 04:22:03
    3[|                         0.7%]
  Mem[||||||||||||||||||||576M/3.82G]
  Swp[                      0K/3.82G]

    PID USER      PRI  NI  VIRT   RES   SHR S CPU%▽MEM%   TIME+  Command
  10772 lehung     20   0 27304   840   744 R 200.  0.0  0:10.42 ./a.out

其实与上面的过程相关的两个主要的系统调用就是:

int sched_setaffinity(pid_t pid, size_t cpusetsize,
                             const cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize,
                             cpu_set_t *mask);

感兴趣的同学可能查看一下上面的两个函数的手册。

  • OMP_SCHEDULE,这个环境变量主要是用在 OpenMP 关于 for 循环的调度上的,他的规则为 OMP_SCHEDULE=type[,chunk],其中 type 的取值可以为 static, dynamic, guided, auto 。并且 chunk size 是可选的,而且他的值是一个正整数。如果这个环境变量没有定义,默认的调度方式是 dynamic 并且 chunk size = 1 。

总结

在本篇文章当中主要给大家介绍了一些经常使用的 OpenMP 系统环境变量,设置环境变量有时候能够更加方便的设置程序,同时有些环境变量对应一些 OpenMP 的动态库函数。以上就是本篇文章的所有内容希望大家有所收获!


更多精彩内容合集可访问项目:http://github.com/Chang-LeHung/CSCore

关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。

本文转载于网络 如有侵权请联系删除

相关文章

  • Java之键盘输入语句Scanner

    文章目录键盘输入语句1.介绍2.步骤3.案例演示键盘输入语句1.介绍在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。Input.java,需要一个扫描器(对象),就是Scanner2.步骤导入该类的所在包,java.util.*创建该类对象(声明变量)调用里面的功能3.案例演示要求:可以从控制台接收用户信息,【姓名,年龄,薪水】 //演示接受用户的输入 //步骤 //Scanner类表示简单文本扫描器,在java.util包 //1.引入/导入Scanner类所在的包 //2.创建Scanner对象,new创建一个对象,体会 //myScanner就是Scanner类的对象 ScannermyScanner=newScanner(System.in); //3.接收用户输入了,使用相关的方法 System.out.println("请输入名字"); //当程序执行到next方法时,会等待用户输入~~~ Stringname=myScanner.next();//接收用户输入字符串 System.out.println(&qu

  • dotnet 修复 ILLinkTasksAssembly 特性的值的计算结果无效

    在加上ILLink的项目里面,在升级到.NET6预览版,有一些项目将会构建不通过,或者有些C++CLI项目加载失败。提示元素UsingTask中“AssemblyFile”特性的值“$(ILLinkTasksAssembly)”的计算结果“”无效。原因就是.NET6预览版里面,或者自己的设备上ILLinkTasksAssembly属性定义失效解决方法是先创建一个空白项目,找找自己本地的ILLinkTasksAssembly定义是否存在,默认在SDK里面是存在Microsoft.NET.ILLink.Tasks的。如果发现自己的设备上不存在Microsoft.NET.ILLink.Tasks这个文件夹,那么请将dotnetsdk卸载重新安装,或者安装更新版本的sdk然后查看自己的环境变量,是否有设置特定版本的dotnetsdk如果有设置,就删除此项值或者修改为更新版本创建空白项目,找找自己本地的ILLinkTasksAssembly定义的做法是在空项目的csproj里面添加如下代码,用来输出ILLink的路径<TargetName="Foo"BeforeTarg

  • 用计算机算法和X光扫描仪,MIT的透视技术让你不拆封就能读信!

    大数据文摘出品来源:WSJ编译:苏苏一个国际研究小组利用计算机算法和专为牙科研究设计的x光扫描仪,在不打开信件的情况下,“打开”了一封自1697年起就封口并折叠严密的信件秘密。周二发表在《自然通讯》杂志上的一篇论文描述了这封信的“虚拟展开”——这是一个为期四年的研究项目的高潮——它指出研究历史悠久的锁信难题的新方法。“锁信”是一个术语,用来描述在19世纪中期信封还未被广泛使用之前,人们折叠信纸来隐藏信件的内容。“这是通信领域的梦想成真,”麻省理工学院(MassachusettsInstituteofTechnology)研究图书馆(researchlibrary)的管理员贾娜·丹布罗吉奥(JanaDambrogio)说。她是这篇论文的11位作者之一。布蕾妮收藏的一封未开封的信。专家表示,用于揭示信件内容的技术,包括一种被称为x射线微断层扫描的成像技术,也可以应用于医疗保健和工程。锁信的复杂性取决于寄信者和收信者对锁信的专长,以及他们希望信件内容在邮寄过程中不易被识别的程度。有些信件被折叠了几十次,最后只有扑克牌大小。历史学家们渴望阅读这些信件,因为它们能让人们了解17世纪欧洲的日常生活

  • python字典的值可以修改吗

    python中字典的值是可以被修改的,首先我们得知道什么是修改字典修改字典向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:#!/usr/bin/python dict={'Name':'Zara','Age':7,'Class':'First'}; dict['Age']=8;#updateexistingentry dict['School']="DPSSchool";#Addnewentry print"dict['Age']:",dict['Age']; print"dict['School']:",dict['School'];复制以上实例输出结果:dict['Age']:8 dict['School']:DPSSchool复制字典中的键

  • 到底什么是皮基站?

    前几天,中国移动公布了一条中标信息,圈里的小伙伴们应该都看到了: 花了9.6亿,采购了8.32万台的“4G皮基站”,平均下来,每台也有1万多呢。那么问题来了,大家听说过微基站、宏基站,这个“皮基站”,是个啥玩意?不是说马上要启动5G网络建设了吗?买这么多4G皮基站,是干什么用?皮基站,既不是皮做的基站,也不是调皮捣蛋的基站。它的真名,叫做PicoSite,也简称皮站。Pico是什么意思?百万分之一,微微,通常指非常微小。 百万分之一微小的基站,这是什么鬼?微米大小的基站?显然不太可能,现在的技术还没有那么先进。其实,皮基站是一种比微基站更小的基站,为了体现级别差距,所以用了pico(微微)这个词。根据3GPP组织的规则,无线基站分为四类,分别是宏基站、微基站、皮基站和飞基站。哈哈,没错,除了皮基站,还有一个更奇葩的“飞基站”,长见识了吧?我们来看看这四种基站的区别:这四种基站,说白了,就是根据功率来划分的。宏基站功率最大,覆盖范围也就最大。飞基站功率最小,覆盖范围自然最小。以前小枣君给大家介绍过宏基站和微基站。像下面这样的,大大的,经常在室外布设的,就是宏基站:宏,就是宏大像这样小小的

  • Anaconda:安装或更新 Python 第三方包

    conda和pip简介condaconda是包及其依赖项和环境的管理工具。适用语言:Python,R,Ruby,Lua,Scala,Java,JavaScript,C/C++,FORTRAN。适用平台:Windows,macOS,Linux用途:快速安装、运行和升级包及其依赖项。在计算机中便捷地创建、保存、加载和切换环境。如果你需要的包要求不同版本的Python,你无需切换到不同的环境,因为conda同样是一个环境管理器。仅需要几条命令,你可以创建一个完全独立的环境来运行不同的Python版本,同时继续在你常规的环境中使用你常用的Python版本。——conda官方网站conda为Python项目而创造,但可适用于上述的多种语言。conda包和环境管理器包含于Anaconda的所有版本当中。pippip是用于安装和管理软件包的包管理器。pip编写语言:Python。Python中默认安装的版本:Python2.7.9及后续版本:默认安装,命令为pip Python3.4及后续版本:默认安装,命令为pip3 pip名称的由来:pip采用的是递归缩写进行命名的。其名字被普遍认为来源于2处:

  • 我写代码很厉害吗?那都是同行的衬托。

    代码水平是一个有趣的事,衡量别人的水平很有趣,衡量自己的水平也很有趣。现在虽然说[有趣],但回想起来,其实也是一把辛酸史。2008年我刚毕业,那一年,是金融危机爆发的一年,也许也是年景不好,工作都特别难找,连网吧网管都有抢的。当时的我,虽然学习成绩在年级不是最好的,但实践能力还是很有自信的。所以满怀着希望,就进入了这个社会。结果,社会狠狠给了我一棒子。找工作嘛,毕业生无非是网络应聘和招聘会赶场。可看了成百上千的软件岗位,居然发现个奇怪的事,用人单位要求会的东西,我一样也不会。不过那也硬着头皮,尝试着投简历找工作。结果自然除了没有回音的,就只剩被叫去面试并被当面羞辱这两种结果。经过毕业前半年的努力尝试,终于领悟了,原来在学校学过的技术都没有用。不止学的肤浅,而且学的技术过时。我这种水平的毕业生,除了培训机构想骗我的钱以外,不会有任何用人单位有培养我做研发的想法。所以,我只能端正态度,从软件行业外围做起,从一切可赚钱的工作做起。换工作,换工作,换工作。。。。然后在每个夜晚攻读C#相关技术,神奇的度过了一年。然后,终于有机会做真正软件工作了。因为曾经是面试中的失败者,所以本着谦虚和学习的态度

  • 微软为华为定制了一个“烂笔头小冰”,让人想起了老罗的“闪念胶囊”

    微软全球执行副总裁——沈向洋在刚刚过去的第六代小冰发布会上,微软和华为走到了一起。小冰产品总监徐翔宣布,微软小冰将于今日上线华为手机,所有升级至智能助手8.2版本及以上的华为手机(包括华为和荣耀品牌)用户都可以立刻体验。屏幕右滑,就可以打开小冰。华为手机上的微软小冰到底有哪些功能,需要体验过后才知道。不过,微软表示,该版本小冰除了提供各平台通用的小冰产品体验外,还为华为手机用户特别推出了帮助用户记录信息等多个任务完成型产品技能。现场,徐翔现场展示了特意为华为手机打造的“烂笔头小冰”功能。这个功能像一个语音备忘录,可以随时让小冰帮你记录日常的各种事情,不禁让人想起了锤子手机的“闪念胶囊”。视频内容虽然两者的出发点相似,但是产品形态、交互逻辑以及最终实现并不一样。小冰充分发挥了自己在人工智能领域的技术积累,可以用各种自然的方式提取记忆,并通过语音快速回答相应的问题。此外,小冰还改头换面,彻底抛弃了以前的形象,并且由2D变成了3D(如下图所示)。至于美不美,这得用户来评判。当然,新一代的小冰远不止这些改变,接下来就位大家一一讲述。 ▌4年时间,6次迭代,终于迎来EQ+IQ2014年5月29

  • MySQL 大数据操作注意事项

    MySQL大数据操作注意事项http://netkiller.github.io/journal/mysql.parallel.html摘要1.关于deletedeletefrommytable必死无疑,你需要分批删除,尽量缩小每个批次删除的记录数,delete是可以并行执行的,你可以同时运行多个删除操作 mysql>showprocesslist; +--------+-----------------+---------------------+-----------+---------+-------+-----------------------------+--------------------------------------------------------+ |Id|User|Host|db|Command|Time|State|Info| +--------+-----------------+---------------------+-----------+---------+-------+-----------------------------

  • 以 Cloud Native 理念构建更健壮的在线教育平台

    导语2017年“云+未来”峰会即将在深圳盛大举行,本次峰会CloudNative技术专场将在7月6日下午举行。CloudNative专场给各家提供了针对OpenStack应用以及背后填坑之路作深度探讨的机会。现在让我们一起回顾下去年各位嘉宾在在现场分享了哪些云上的心得体会以及CloudNative云原生架构上的亲身实践。本文是极客学院联合创始人&CTO姚尚朗在2016年腾讯“云+未来”峰会CloudNative专场有关《以CloudNative理念构建更健壮的在线教育平台》分享的回顾。姚尚朗:《以CloudNative理念构建更健壮的在线教育平台》极客学院进行了国内首个在线教育领域的CloudNative实践分享。极客学院是国内最大的IT职业在线教育平台,以CloudNative理念构建更健壮的在线教育平台,极客学院的联合创始人&CTO姚尚朗分享了腾讯云上如何实践CloudNative,从早期的服务器单点到基于腾讯云的服务器集群,应用CloudNative的持续集成、自动化部署、业务微服务化的解决之道,成功解决了业务耦合高、逻辑复杂等一系列挑战。姚尚朗提到在业务层面以及

  • 惯性、趋势、外力(因) 业精于勤,荒于嬉;行成于思,毁于随;狼性

  • 常用正则表达式

    验证数字:^[0-9]*$  验证n位的数字:^\d{n}$  验证至少n位数字:^\d{n,}$  验证m-n位的数字:^\d{m,n}$  验证零和非零开头的数字:^(0|[1-9][0-9]*)$  验证有两位小数的正实数:^[0-9]+(.[0-9]{2})?$  验证有1-3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$  验证非零的正整数:^\+?[1-9][0-9]*$  验证非零的负整数:^\-[1-9][0-9]*$  验证非负整数(正整数+0)^\d+$  验证非正整数(负整数+0)^((-\d+)|(0+))$  验证长度为3的字符:^.{3}$  验证由26个英文字母组成的字符串:^[A-Za-z]+$  验证由26个大写英文字母组成的字符串:^[A-Z]+$  验证由26个小写英文字母组成的字符串:^[a-z]+$  验证由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$ 

  • 大型网站系统架构的演化

    大型网站系统架构的演化     前言:         一个成熟的大型网站系统架构,比如淘宝,京东等的系统架构不是开始设计就具备完整的高性能、高可用、安全等特性。       它是随着客户量的增加,业务功能的扩展而逐渐完善起来的,在这个模式中,开发模式,技术架构,团队规模,设计思想都在       逐渐的完善。       所以系统架构是随着业务扩展而逐渐完善起来的,并不是一蹴而就。       最开始的网站架构:               应用、文件、数据分离:          随着业务的扩展,一台服务器已经无法满足用户的需求,所以要把应用、数据库、文件各自部署到不通的服务器上        并根据服务器的不同配置不同的硬件、已达到最佳的性能效果       利用缓存改变网站性能:         在硬件优化的同时,也要考虑到软件的优化,大部分的网站系统中,都会使用到缓存技术来改善应用的性能,使用缓存       主要源于热点数据的存在,大部分网站的访问都会遵循28规则(即80%的访问量是访问的20%

  • 【bzoj3512】DZY Loves Math IV 【杜教筛】

    题目链接 题意:求∑ni=1∑mj=1φ(ij)∑i=1n∑j=1mφ(ij)模10000000071000000007的值。n<=100000,m<=1000000000n<=100000,m<=1000000000。 题解:首先我们有一个结论。 若|μ(n)|=1|μ(n)|=1,则φ(nm)=∑k|gcd(n,m)φ(nk)φ(m)φ(nm)=∑k|gcd(n,m)φ(nk)φ(m)。 怎么证? ∑k|gcd(n,m)φ(nk)φ(m)∑k|gcd(n,m)φ(nk)φ(m) =φ(m)∑k|gcd(n,m)φ(nk)=φ(m)∑k|gcd(n,m)φ(nk) =φ(m)∑k|gcd(n,m)φ(n)φ(k)=φ(m)∑k|gcd(n,m)φ(n)φ(k) =φ(n)φ(m)∑k|gcd(n,m)1φ(k)=φ(n)φ(m)∑k|gcd(n,m)1φ(k) =φ(n)φ(m)∑k|gcd(n,m)φ(gcd(n,m))φ(k)φ(gcd(n,m))=φ(n)φ(m)∑k|gcd(n,m)φ(gcd(n,m))φ(k)φ(gcd(n,m)) =φ(n)φ(m

  • 一本通 1313:【例3.5】位数问题 (递推/动态规划)

    一本通1313:【例3.5】位数问题 目录一本通1313:【例3.5】位数问题【题目描述】【输入】【输出】【输入样例】【输出样例】【相关知识】【我的答案】 时间限制:1000ms内存限制:65536KB 提交数:15814通过数:8606 【题目描述】 在所有的N位数中,有多少个数中有偶数个数字3?由于结果可能很大,你只需要输出这个答案对12345取余的值。 【输入】 读入一个数N(N≤1000)。 【输出】 输出有多少个数中有偶数个数字3。 【输入样例】 2 复制 【输出样例】 73 复制 【相关知识】 特别注意,零是特殊的偶数! 要计算在N位数中,含有奇数个(或偶数个)数字3(或者1-9之间的任何数字)的数的个数,可以逐个由第1位推导。 【我的答案】 #include<bits/stdc++.h> usingnamespacestd; constintMAXLEN=1003; intodd[MAXLEN],even[MAXLEN]; intn; intk=9; intmain(){ cin>>n; odd[1]=1; even[1]=9;

  • 「ZJOI2022」众数

    显然只有原序列中的数有可能成为答案 于是离散化之后每个数独立,枚举每个数 这种问题可以考虑根号分治 \(c_i>B\),我们可以枚举中间那一段的颜色变成了什么,复杂度\(O(n)\) \(c_i\leqB\),如果中间那一段的\(c_j>B\),可以在\(j\)处类似上面那种方法处理一下,否则中间这一段最多\(B\)步,直接预处理\(f[i][j]\)表示\(i\)出发走\(j\)步最近走到哪,复杂度\(O(cB)\) 于是\(O(n\sqrtn)\) #include<bits/stdc++.h> usingnamespacestd; #defineRep(i,a,b)for(inti=a;i<=b;i++) #define_Rep(i,a,b)for(inti=a;i>=b;i--) #defineRepG(i,u)for(inti=head[u];~i;i=e[i].next) constintN=2e5+5; constintM=505; typedeflonglongll; typedefdoubledb; #definech

  • 根据省份等地址获取经纬度,或根据经纬度获取地址信息

    在web开发涉及地图操作的时候或者移动客户端开发中有时候有以下需求: 根据省份等地址获取经纬度,或根据经纬度获取地址信息 下面主要记录通过百度提供的API的一个解决方案: 在百度开发平台中提供了这样一个叫Geocoding的API,这个API用于提供从地址到经纬度坐标或者从经纬度坐标到地址的转换服务,使用的是http协议,返回JSON或者XML数据。 地理编码:即地址解析,由详细到街道的结构化地址得到百度经纬度信息,例如:“北京市海淀区中关村南大街27号”地址解析的结果是“lng:116.31985,lat:39.959836”。同时,地理编码也支持名胜古迹、标志性建筑名称直接解析返回百度经纬度,例如:“百度大厦”地址解析的结果是“lng:116.30815,lat:40.056885”,通用的POI检索需求,建议使用PlaceAPI。 逆地理编码:即逆地址解析,由百度经纬度信息得到结构化地址信息,例如:“lat:31.325152,lng:120.558957”逆地址解析的结果是“江苏省苏州市虎丘区塔园路318号”。 使用限制: 百度地图GeocodingAPI是一套免费对外开放的

  • spring boot实现国际化(全面代码)

    前言 这是我的第一篇博客,也是原文是大神“刘东”的代码。之所以重新再次创建在自己的博客,第一是想保存一篇在成长中解决了自己难题的文章,其次是把大神的代码拷贝到本地时遇到了一些小问题,但是后来解决了,所以对大神的代码小有改动作以保存。 这Demo是springboot+template模板作为示例,大神说:在项目开发中,可能遇到需要国际化,而支持国际化确是一件很头疼的事,但是springboot给出了一个非常理想和方便的方案。 一、准备工作 pom.xml 1<?xmlversion="1.0"encoding="UTF-8"?> 2<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4<modelVersi

  • ubuntu下解决wireshark权限问题

    wireshark要监控eth0,但是必须要root权限才行。但是,直接用root运行程序是相当危险,也是非常不方便的。解决方法如下:1.添加wireshark用户组sudogroupaddwireshark2.将dumpcap更改为wireshark用户组sudochgrpwireshark/usr/bin/dumpcap3.让wireshark用户组有root权限使用dumpcapsudochmod4755/usr/bin/dumpcap4.将需要使用的用户名加入wireshark用户组,我的用户名是craftorsudogpasswd-acraftorwireshark参考:http://www.cnblogs.com/ddtpower/archive/2012/12/20/ubuntu_wireshark_dumpcap.html

  • C# 多线程处理相关说明: WaitHandle,waitCallback, ThreadPool.QueueUserWorkItem

    classTestThread { staticvoidMain() { //使用WaitHandle静态方法阻止一个线程,直到一个或多个同步对象接收到信号 WaitHandle[]waitHandles=newWaitHandle[] { newManualResetEvent(false), newManualResetEvent(false) }; WaitCallbackwaitCallback=newWaitCallback(MyThreadWork); WaitCallbackwaitCallback2=newWaitCallback(MyThreadWork2);//增加线程工作类型 ThreadPool.QueueUserWorkItem(waitCallback,"第一个线程"); ThreadPool.QueueUserWorkItem(waitCallback,"第二个线程"); MyStatemyState=newMyState("第三个线程",100,waitHandles[0]);//增加自定义的线程参数类型 ThreadPool.QueueUs

  • 20180925-3 效能分析

      作业要求参见[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2145] git地址:https://git.coding.net/KamiForever/newwf.git 一、得出程序运行时间 运行截图如下: 第一次运行时间为0.564s 第二次运行时间为0.402s 第三次运行时间为0.406s 平均运行时间为:0.457s CPU参数:Intel(R)Core(TM)i7-8750MCPU@2.20GHz 2.20GHz 二、猜测程序瓶颈 猜测一:在进行字符输入的时候会用很多时间 while((c=getchar())!=EOF){ if((c>=65&&c<=90)||(c>=97&&c<=122)){ if(c>=65&&c<=90)c+=32; word[i++]=c; before=1; } else{ if(before){ word[i]='\0'; Hash(word); i=0; befo

相关推荐

推荐阅读