<< 四月 2015 | 首页 | 六月 2015 >>

Arduino+RFID RC522 +继电器 - MicroHao - 博客园

连线部分

  Arduino                                               RC522 (工作电压3.3V)

· D5                   <------------->             RST    (这个脚不接貌似也可以)

· D10                 <------------->             SDA   (RC522中即为CS)

· D11                 <------------->             MOSI

· D12                 <------------->             MISO

· D13                 <------------->             SCK

· VCC                 <------------->             VCC

· GND                 <------------->             GND

 

                                                            继电器模块控制端

· D7                 <------------->              In1

· VCC               <------------->             VCC

· GND               <------------->             GND

保留作者或是译者。

复制代码

  1 //整理者:极客工坊bg1lsy ([email protected])
  2 //整理时间:2013.05.25
  3 #include <SPI.h>
  4 #include <RFID.h> 
  5 
  6 RFID rfid(10,5);   //D10--读卡器MOSI引脚、D5--读卡器RST引脚
  7 
  8 int led = 9;
  9 int relay=7;
 10 
 11 bool state=true;
 12 void setup()
 13 {
 14   Serial.begin(9600);
 15   SPI.begin();
 16   rfid.init();
 17   pinMode(led, OUTPUT);  
 18   pinMode(relay,OUTPUT);
 19   digitalWrite(relay,HIGH);
 20 }
 21 
 22 void loop()
 23 {
 24   unsigned char type[MAX_LEN];
 25   //找卡
 26   if (rfid.isCard( type)) {
 27     Serial.println("Find the card!"); 
 28     ;
 29     // Show card type
 30     ShowCardType(type);
 31     //读取卡序列号
 32     if (rfid.readCardSerial()) {
 33       Serial.print("The card's number is  : ");
 34       Serial.print(rfid.serNum[0],HEX);
 35       Serial.print(rfid.serNum[1],HEX);
 36       Serial.print(rfid.serNum[2],HEX);
 37       Serial.print(rfid.serNum[3],HEX);
 38       Serial.print(rfid.serNum[4],HEX);
 39       Serial.println(" ");
 40       ShowUser(rfid.serNum);
 41     }
 42     //选卡,可返回卡容量(锁定卡片,防止多数读取),去掉本行将连续读卡
 43     Serial.println(rfid.selectTag(rfid.serNum));
 44   }
 45 
 46   rfid.halt();
 47 }
 48 
 49 void ShowCardType( unsigned char* type)
 50 {
 51   Serial.print("Card type: ");
 52   if(type[0]==0x04&&type[1]==0x00) 
 53     Serial.println("MFOne-S50");
 54   else if(type[0]==0x02&&type[1]==0x00)
 55     Serial.println("MFOne-S70");
 56   else if(type[0]==0x44&&type[1]==0x00)
 57     Serial.println("MF-UltraLight");
 58   else if(type[0]==0x08&&type[1]==0x00)
 59     Serial.println("MF-Pro");
 60   else if(type[0]==0x44&&type[1]==0x03)
 61     Serial.println("MF Desire");
 62   else
 63     Serial.println("Unknown");
 64 }
 65 
 66 void ShowUser( unsigned char* id)
 67 {
 68   //EE 9B 9C 38 D1 
 69   if( id[0]==0xEE && id[1]==0x9B && id[2]==0x9C && id[3]==0x38 ) {
 70     Serial.println("Hello Mary!");
 71     state=RelayStatus(state);
 72   } 
 73   else if(id[0]==0x24 && id[1]==0x12 && id[2]==0xE0 && id[3]==0x13) {
 74     Serial.println("Hello MicroHao!");
 75     state=RelayStatus(state);
 76   }
 77   else{
 78     Serial.println("Hello unkown guy!");
 79     BlinkLED();
 80 
 81   }
 82 }
 83 bool RelayStatus(bool status)
 84 {
 85   if(status)
 86   {
 87     digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
 88 
 89     digitalWrite(relay,LOW);
 90     return false;
 91   } 
 92   digitalWrite(led, LOW);   // turn the LED on (HIGH is the voltage level)
 93 
 94   digitalWrite(relay,HIGH);
 95   return true;
 96 }
 97 void BlinkLED()
 98 { 
 99   digitalWrite(relay,HIGH);
100   for(int i=0;i<3;i++)
101   {
102     digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
103     delay(1000); 
104     digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
105     delay(1000);
106   } 
107 }
复制代码
 

 参考:

http://blog.davidou.org/archives/684

阅读全文……

标签 :

云上Java System Profiling与Debugging——蚂蚁金服观察与实践-CSDN.NET

常见问题解决思路

下面介绍一下处理一些常见的问题时,使用ZProflier和ZDebugger系统与使用传统工具在流程和思路上的一些区别。一个新上线的系统如果处理能力达不到我们的预期,或者一个老的系统处理速度突然下降了,抑或频繁抛出异常,这些都促使我们去思考系统存在性能问题该优化了,那我们通常会碰到的性能问题有OOM、CPU占用率高、Load高、频繁GC等。OOM的现象为Java进程直接退出,出错日志里可以看到OutOfMemoryError的异常。如果发现频繁的做MajorGC甚至是FullGC,一般也是OOM的前兆。解决此类问题的主要手段是分析heapdump。

JDK自带jmap工具,使用命令jmap-dump:live,format=b,file=heap.bin即可将Java进程的heap内存按照HPROFBinaryFormat的格式dump

 

图1ZProfiler

到名字为heap.bin的文件里。命令中的live参数,意味在dump之前会做一次FullGC,保证dump出来的对象都尽量是活的对象,减少heap.bin的大小,降低工具的分析时间。是否要设置这个参数要视具体问题,比如想知道old区到底为什么会增长这么快,都增加了些什么对象呢?这个时候你可能没必要去加live参数了,只要连续做两次heapdump,然后做一次内存对比,就知道这段时间内增加了哪些对象。但如果你想找出一些长时间不释放的对象,分析其根引用树是怎样的,这时加上live参数来dump就比较合理。

常用的heapdump分析工具是EclipseMemoryAnalyzerTool,简称MAT。这款工具功能很强大,但正由于它过于强大,因此给初学者带来的学习成本也比较高。其次它是一个客户端程序,需要安装在本地,因此它也受限于本地的机器性能,比如本机内存就4GB,而heap文件大小为8GB,这时MAT就无法完成分析工作了。因为MAT本身也是Java程序,它在分析大heap时会出现不断做GC,甚至fullgc等异常情况,导致分析没有结果。针对这些问题,我们的性能分析产品ZProfiler精减了部分不常用的功能,保证绝大部分用户使用上的简便性。另外ZProfiler是个Web系统,运行在一台服务器上,分析能力不再受限于开发人员的机器性能,而WebUI操作的方式也大大减轻了开发人员的工作量。

CPU高的问题需要分层来考虑,首先检查操作系统层面的一些原因,比如频繁的memorypaging,可能导致Java应用在内核态花费的时间较多。也可以使用perftop检查JVM内部比如JIT,GC线程的CPU使用情况。如果JIT线程使用的CPU较高,就需要看看codecache或者其他JIT相关参数是否设置合理;如果是gc线程,就需要进一步分析gclog,然后调整GC相关的参数等。

排除以上原因之后,基本可以确认是Java代码的问题,可以使用ZProfiler提供了HotMethodProfiling功能查看热点方法,这个后面有详细描述。

Load高意味着运行的线程或者运行队列里的线程比较多,此时可以通过线程dump进行排查。线程dump,可以使用JDK自带的工具jstack,执行命令jstack即可,会将进程的所有Java线程给dump出来。如果还想跟踪native的堆栈,需要增加-m参数。当拿到线程dump之后,按照线程状态进行归类【注:JVM里dump出来的线程日志,线程的状态并不是100%的准确,细节可以参考JVMBug:多个线程持有一把锁?】。对于同一个系统,Load高的机器RUNNABLE态的线程数目一定比Load低的机器多。我们可以通过threaddump来分析这些多出的线程都在干嘛,从而找到Load高的原因。

针对线程分析,ZProfiler不仅仅从状态粒度提供了分析,还从锁粒度以及热点栈粒度做了统计分析,ZProfiler可以帮助用户看到一把锁影响到了哪些线程,哪个线程持有这把锁,那些线程正在等待这把锁,对于线程数因为同步锁的问题突然大增基本可以通过ZProifiler的分析结果看出问题在哪里。同样的,对于某个方法在哪些线程里或者运行态的线程里正在栈上执行,ZProfiler也提供了统计,方便用户排查Load高等问题。

 

图2 ZDebugger 

GC频繁是Java程序最常见的问题之一,大多数情况下都是由于相关参数配置不合理导致的。HotSpotGC相关的设置参数比较多,要找到比较合理的参数设置,首先要对应用的内存情况有一个总体的了解:比如应用运行稳定后,LiveDataSize大概是多少,这个会影响到-Xmx/-Xms/-Xmn的设置大小【注:CharlieHunt/BinuJohn合写的JavaPerformance提供了很好的Guide】;运行过程中创建的对象temp对象和longlived对象的大概比率,这个会影响到heap老区新区的设置比例。

查看GC情况通常有两种方式,一种是打开gclog相关的参数,事后分析gclog;另外一种是实时获取GC信息,可以打开JMX接口通过相关的MXbean获取,或者通过jstat命令。

gclog分析是个苦差,因为gclog输出的信息非常多,但是很多时候我们需要关注的是长期的趋势和整体的统计信息,人工分析太耗时间。目前也有一些不错的gclog分析工具,比如GCViewer。ZProfiler除了做了和GCViewer类似的工作之外,前面谈到过,ZProfiler系统本身就是部署在金融云里的,这意味着用户可以非常方便地通过简单的WebUI操作把gclog直接复制到ZProfiler上来分析。另外,我们也正在开发一些更高级的一些功能,在gclog分析完成后,给用户一些直接的建议,比如是否GCPause的时间过长,设置的GC参数应该如何调整,GC花费的CPU时间是不是过长等。

实时获取GC信息方面,VisualVM的VisualGC插件做的不错,非常直观地显示出当前应用的GC情况,但是分析方面做的不够。ZProfiler同样使用MXBean的方式获取实时的GC信息,将更有价值和更具统计意义的信息展示出来。而对于云上难以复现、偶发性的问题,我们推荐使用在线调试平台ZDebugger对运行中的程序进行在线调试。在线调试的原则是方便用户简单快速地打开调试器,且不能影响应用的正常运行。基于此思路,ZDebugger设计为基于Jetty的Web服务器,用户使用浏览器即可发送调试命令。调试器使用JDWP协议通过网络与被调试的JVM后端连接,在不重启JVM的情况下动态打开JVM调试功能,JVM在不阻断应用运行的前提下即时抓取断点处的运行信息并将其返回。

JDK定制

最后谈一下我们在OpenJDK中的一些定制。主要加入了Debug-on-Late-Attach(aka.DOLA)、Fast-SnapshotAt-Breakpoint(aka.FSAB)以及HotMethodProfiling等功能【注:后续我们也会和OpenJDK社区讨论怎么能把这些改动标准化,并贡献到社区,其中的一些部分已经开始了讨论】。

DOLA即在不重新启动JVM的情况下,可以把“有限的”的Java调试功能打开。这个功能对于生产环境的调试来说非常有意义。尽管目前主流的商业JVM基本都宣称“full-speeddebugging”,但在实际的使用中,我们没有多少人直接把JVM的调试能力在生产环境直接打开【注:在JVM启动时加-agentlib:jdwp设置参数,就可以打开JVM调试】,因为事实上还是对应用的性能有影响的。比如,对于JIT的影响,调试模式下EscapeAnalysis功能是被自动关掉的,而且一些解释器的fastpath也可会受到影响,而走slowpath。所以当线上问题出现时,往往要求重新启动问题JVM,把Debug功能打开调试,而尴尬在于,重启JVM往往会导致很难再现问题场景。这个是我们改造JDK,加入DOLA的初衷。

DOLA允许用户通过jcmd命令动态把JVM的“有限的”调试功能打开,通过ZDebugger,用户可以对被调试的JVM设置断点以及查看变量的值,这两个功能对我们来说已经足够帮助我们发现和诊断线上的大部分问题。

DOLA定制解决的难点主要在这么几个方面。

 

  • jdwpagent改造,支持Agent_OnAttach接口,这样可以通过扩展的jcmd命令把jdwpagent在运行时加载到TargetJVM。
  • Interpreter改造,在Bytecodepatch路径上支持断点设置逻辑【注:关于HotSpotBytecodepatch,感兴趣的读者可以参考RewriteBytecodes/RewriteFrequentPairs等相关实现机制】。
  • 方法De-optimization机制改造:标准的HotSpotJVM实现,用户设置断点,设置断点的当前方法被deoptimize到解释器版本。而我们定制的HotSpot会把所有的方法在这个点上都de-optimize掉,这是由于我们在JVM启动的时候没有开启调试,JIT就没有记录用于设置断点的方法dependency信息,De-optimize所有的方法会帮助JIT在后续的编译版本里记录下dependency信息。

 

FSAB的作用是配合Zdebugger系统的watchpoint调试模式。这种模式借鉴自Google的clouddebugger,其应用场景是:在云环境中,传统的SingleStep调试模式根本不可行,因为设置断点并单步调试,会造成线程阻塞,导致系统出现超时等各种无关的错误,甚至威胁整个系统正常运行。

而watchpoint调试模式是在断点停住之后,自动将调用堆栈、各层的局部变量,以及用户设置的表达式的值快速地取出来,然后Disable断点,并Continue当前执行。断点需要用户主动Enable,才会再次生效。这种模式可以尽量减少调试动作对运行系统的影响。

取局部变量最早是直接使用jdi接口实现的。为了一次断点触发能给用户提供足够的信息,会递归地将每个局部变量的成员都取出来。当设置为递归四层的时候,jdi的性能问题暴露了出来,断点触发之后停顿时间长达几秒钟。因此我们扩展了jdwp,增加了FSAB,使用Native方法直接批量获取数据。

另外我们还提供了两项比较独特的功能。一个是基于watchpoint调试模式的“多人在线调试”,即ZDebugger可以让用户创建或者订阅自己感兴趣的断点,当断点触发时将相关信息推送给订阅该断点的用户。这样多个用户可以互不干扰地对同一个运行系统进行调试。另一个是自动跟踪用户关注的数据。首次断点触发后,通过FSAB获取局部变量成员数据的时候默认是广度遍历。最终在用户界面上的展示是一颗可以展开的树,用户展开去查看自己关注的成员。这时系统会记录下用户关注的是哪个成员,下次断点触发通过FSAB获取数据时,会根据用户关注成员的路径进行深度遍历。获取更多用户关注的路径上的数据,而忽略其他分支。

HotMethodProfiling顾名思义就是热点函数剖析。热点函数统计剖析是性能分析中很重要的一项工作。因为按照已有的经验,程序运行过程中大部分时间都花费在少量的代码上。为了优化工作的投入产出比,应该先考虑优化程序中的热点函数。

热点函数统计有两种方法,一种是插桩,一种是采样。前者的例子有gprof,通过编译时增加一个特殊的编译选项,在所有函数的入口和出口插桩。运行时,在桩函数中记录时间等信息,输出到结果文件。事后可以得到每个函数精确的调用次数、执行时长以及整个函数调用关系图。其缺点是需要重新编译,而且要程序运行结束后才能拿到结果。后者的例子如perf,通过高频率的定时中断去打断运行中的程序,并在中断处理中记录当前程序运行的上下文信息。这样的结果显然是一种统计意义上的结果。如果采样频率不够高(出于性能考虑,一般也不会特别高),有可能会漏掉一些频繁执行,但每次执行时间短于采样间隔的代码。但其优点是不用重编程序,随时动态开关,马上就能得到结果。

ZProfiler采用是后一种方法。因为在用户态程序中,无法像perf一样采用硬件中断,而是采用了定时信号(linux系统提供了一种SIGPROF定时器)。我们提供了start和stop两个jmx命令,其实就是启动和停止一个定时器。在定时器信号的处理函数中去回溯Java调用栈。

回溯Java调用栈,ZProfiler使用了HotSpotJVM的一个非标准接口AsyncGetCallTrace(据说Oracle商业软件JavaMissionControl的MethodProfiling也是用的这个接口)。通过调用这个接口可以获得当前被定时器信号打断的线程的Java调用栈,而不需要等到JVM的safepoint才能收集线程堆栈。依赖safepoint来收集堆栈(比如通过调用Thread.getAllStackTraces)的profiling机制是有缺陷的,往往收集到的热点堆栈并不精确。在运行JITed的代码情况下,safepoint的时机往往是由JIT来决定的,比如在执行一些非常Hot的循环时,为了保证执行效率,JIT生成的代码就不会插入safepoint的轮询。这样的情况下,依赖safepoint的profiling机制就不会profiling到这些热点。有关AsyncGetCallTrace的使用,感兴趣的读者可以在网上找到更多的资料,或者可以直接阅读HotSpot的源代码,理解它的原理和用法。

阅读全文……

Arduino教程汇总贴(2014.12.29更新)-Arduino中文社区

初识arduino   http://www.arduino.cn/thread-1083-1-1.html
关于Arduino及其周边配件的购买建议 http://www.arduino.cn/thread-11017-1-1.html
常见arduino版本比较   http://www.arduino.cn/thread-1192-1-1.html
关于使用Arduino做开发的二三理解    http://www.arduino.cn/thread-5414-1-1.html


Arduino IDE下载   http://www.arduino.cn/thread-5838-1-1.html
Arduino驱动安装方法   http://www.arduino.cn/thread-1008-1-1.html
Arduino驱动安装失败的解决方法:
Arduino驱动问题一键修复工具beta   http://www.arduino.cn/thread-12349-1-1.html
安装驱动数据无效  http://www.arduino.cn/thread-7531-1-1.html
系统找不到指定文件   http://www.arduino.cn/thread-2485-1-1.html

Arduino入门套件官方视频教程   http://edu.elecspark.com/course/1
Arduino Robot官方视频教程   http://edu.elecspark.com/course/2
Arduino语言参考   http://www.arduino.cn/reference

Cooper Maa的Arduino教程(适合用各种元件学习Arduino的朋友)   http://www.arduino.cn/thread-2814-1-1.html
海神的Arduino模块使用教程(适合用Arduino模块的朋友)    http://www.arduino.cn/thread-3274-1-1.html
珜羽的教程(通俗易懂)    http://www.arduino.cn/thread-4435-1-1.html

2.扩展库的使用
Arduino教程(提高篇)——SR04超声波类库的使用   http://www.arduino.cn/thread-1003-1-1.html
Arduino教程(提高篇)——舵机的驱动   http://www.arduino.cn/thread-1038-1-1.html
Arduino教程(提高篇)——使用EEPROM断电也能保存数据   http://www.arduino.cn/thread-1157-1-1.html 
                                           用共用体结构保存其他类型的数据到EEPROM: http://www.arduino.cn/thread-2684-1-1.html 
Arduino教程(提高篇)——红外遥控(接收篇)  http://www.arduino.cn/thread-1220-1-1.html
Arduino教程(提高篇)——红外遥控(发射篇)  http://www.arduino.cn/thread-1394-1-1.html
使用IRremote库红外遥控家里的电器  http://www.arduino.cn/thread-3618-1-1.html
Arduino教程(提高篇)——驱动12864LCD模块   http://www.arduino.cn/thread-1930-1-1.html

3.进阶
Arduino教程(提高篇)——外部中断的使用   http://www.arduino.cn/thread-2421-1-1.html  
Arduino教程(提高篇)——编写扩展库   http://www.arduino.cn/thread-1009-1-1.html
Arduino教程(提高篇)——使用Visual Studio开发Arduino   http://www.arduino.cn/thread-1683-1-1.html 
Arduino教程(提高篇)——把arduino变成AVRISP烧写器   http://www.arduino.cn/thread-1245-1-1.html
Arduino教程(提高篇)——红外遥控控制舵机  http://www.arduino.cn/thread-1242-1-1.html  
Arduino教程(提高篇)——使用Ethernet构建简易的Web Server   http://www.arduino.cn/thread-8514-1-1.html
在Arduino中使用看门狗定时器   http://www.arduino.cn/thread-2638-1-1.html
串口的高级用法  http://www.arduino.cn/thread-2710-1-1.html 
修改Arduino串口缓冲区大小   http://www.arduino.cn/thread-7885-1-1.html
在Arduino上使用printf格式化输出到串口   http://www.arduino.cn/thread-8366-1-1.html


4.各种传感器、模块使用
传感器扩展板的使用   http://www.arduino.cn/thread-2779-1-1.html
五向倾斜模块  http://www.arduino.cn/thread-2327-1-1.html
旋转编码器   http://www.arduino.cn/thread-2423-1-1.html
无源蜂鸣器模块 http://www.arduino.cn/thread-1513-1-1.html 
DS18B20温度传感器 http://www.arduino.cn/thread-1345-1-1.html 
DHT11温湿度传感器 http://www.arduino.cn/thread-1429-1-2.html
LM35线性温度传感器 http://www.arduino.cn/thread-1055-1-1.html 
韦根协议(26位)及其读取算法   http://www.arduino.cn/thread-2587-1-2.html
GSM/GPRS/GPS系列教程   http://www.arduino.cn/thread-6985-1-1.html

5.实例制作
基于Arduino的数字示波器 http://www.arduino.cn/thread-3703-1-1.html
模型用GPS测速仪  http://www.arduino.cn/thread-3623-1-1.html
Arduino实现自动浇水、遮阳  http://www.arduino.cn/thread-3437-1-1.html
基于arduino 控制的语音控制调节台灯  http://www.arduino.cn/thread-3520-1-1.html
智能壁障小车(带控制端) http://www.arduino.cn/thread-3445-1-1.html
Arduino制作自行车POV制作  http://www.arduino.cn/thread-3748-1-1.html
远程遥控侦查机器人  http://www.arduino.cn/thread-3768-1-1.html
基于Arduino的穿戴式LED灯条表演服  http://www.arduino.cn/thread-3400-1-1.html
Aduino 制作音乐播放器   http://www.arduino.cn/thread-2944-1-1.html

Arduino小车制作教程(巡线、壁障、遥控)   http://www.arduino.cn/thread-3728-1-1.html
人工智能之五子棋机器人——人机对弈   http://www.arduino.cn/thread-1108-1-1.html
基于arduino控制器智能垃圾桶  http://www.arduino.cn/thread-975-1-1.html
Arduino 蓝牙遥控小车  http://www.arduino.cn/thread-2247-1-1.html
Ulink基于微信公众平台的远程物联网控制方案   http://www.arduino.cn/thread-7368-1-1.html
自平衡机器人——蛋黄物语   http://www.arduino.cn/thread-6246-1-1.html
艺术类项目——如影随形   http://www.arduino.cn/thread-7211-1-1.html
基于arduino的迈克尔逊干涉仪测量自动化装置   http://www.arduino.cn/thread-6220-1-1.html


6.Arduino Leonardo专题
Arduino Leonardo 中文介绍  http://www.arduino.cn/thread-1205-1-1.html 
leonardo做的无线鼠标   http://www.arduino.cn/thread-2436-1-1.html
关于leonardo在模拟USB设备后,无法下载的问题   http://www.arduino.cn/thread-1653-1-1.html

7.Arduino Due专题
Arduino Due 中文介绍  http://www.arduino.cn/thread-2216-1-1.html
第三方CANBUS库   http://www.arduino.cn/thread-5735-1-1.html

8.Arduino Yun专题
Arduino Yun 中文介绍  http://www.arduino.cn/thread-4075-1-1.html

9.Arduino Zero专题
Arduino Zero 中文介绍  

10.Arduino Ethernet专题
Arduino Ethernet中文介绍   http://www.arduino.cn/thread-8384-1-1.html

11.Intel Galileo/Edison专题
Intel Galileo/Edison资源汇总贴   http://www.arduino.cn/thread-4526-1-1.html

X.其他
Yeelink-物联网跟我做 http://www.arduino.cn/thread-1142-1-1.html
arduino学习笔记 - Mega 2560+TFT3.2寸屏的演示实验  http://www.arduino.cn/thread-989-1-3.html
Arduino UNO + GP2D12红外测距传感器+LCD1602详细演示过程  http://www.arduino.cn/thread-1107-1-1.html
Arduino Uno + HY-SRF05 超声波测距模块详细讲解演示实验  http://www.arduino.cn/thread-1110-1-1.html
arduino学习笔记 - Arduino Uno + MMA7361三轴加速度传感器   http://www.arduino.cn/thread-1141-1-1.html
AVR学习
AVRGCC用户手册   http://www.arduino.cn/avrgcc/

 

 

Arduino示例教程模块版汇总

1、Arduino示例教程模块版——开始您的Aduino之旅(WINDOWS版)
2、Arduino示例教程模块版——传感器扩展板的使用
3、Arduino示例教程模块版——按键实验
4、Arduino示例教程模块版——模拟声控路灯实验
5、Arduino示例教程模块版——直滑电位器与光互动实验
6、Arduino示例教程模块版——数字抢答器实验
7、Arduino示例教程模块版——超声波测距实验
8、Arduino示例教程模块版——红外遥控实验
9、Arduino示例教程模块版——舵机控制实验
10、Arduino示例教程模块版——人体红外报警实验
11、Arduino示例教程模块版——避障传感器与光互动实验
12、Arduino示例教程模块版——电子琴实验
13、Arduino示例教程模块版——智能环境监控实验

 

Cooper Maa系列教程汇总贴

使用者可以在 Arduino 板子上接上各種電子裝置,例如 LED 燈、喇叭、馬達、開關、溫濕度感測器、紅外線發射與接收器、LCD 顯示裝置,以及 Ethernet, WiFi, XBee, Bluetooth, RFID, GPS 等各種通訊模組。若再配合撰寫一些自動控制的程式,就能利用 Arduino 做出各式各樣的自動控制應用,例如利用溫度感測器控制風扇的運轉、使用可變電阻控制燈光的明暗、控制馬達的轉速、利用紅外線遙控家電/ 利用伺服機 (Servo) 控制機械手臂或機器人,以及製作自走車、飛行器等等。

這系列教學將讓你認識 Arduino,並且向你介紹各種基本電子裝置的使用方法。

教學目標
學習撰寫 Arduino 程式,以及使用各種基本電子裝置,包括: LED, 蜂鳴器、觸動開關、可變電阻、PWM 調光器、光敏電阻、七段顯示器、字元 LCD、74HC595 移位暫存器、Matrix LED、Keypad、伺服馬達、紅外線移動感測器、紅外線測距以及繼電器等。

授課對象
Arduino 進入門檻低,即便你沒有電子電機相關科系的背景,也可以很容易學會使用 Arduino,因此只要具備基本電腦操作能力就可以學習。

认识 Arduino   http://www.arduino.cn/thread-2815-1-1.html 
准备开发环境  http://www.arduino.cn/thread-2823-1-1.html
Lab1 Blinking a LED  http://www.arduino.cn/thread-2853-1-1.html
Lab2 使用按鍵控制 LED 燈號   http://www.arduino.cn/thread-2854-1-1.html
Lab3 控制 LED 灯亮度   http://www.arduino.cn/thread-2855-1-1.html
Lab4 使用电位器调光   http://www.arduino.cn/thread-2871-1-1.html
Lab5 LED Bar Graph    http://www.arduino.cn/thread-2872-1-1.html
Lab6 控制蜂鸣器发声   http://www.arduino.cn/thread-2877-1-1.html
Lab7 使用七段顯示器製作倒數功能   http://www.arduino.cn/thread-2881-1-1.html
Lab8 使用光敏电阻控制 LED 的开关   http://www.arduino.cn/thread-2907-1-1.html
Lab9 在1602 LCD 上显示 "Hello World"   http://www.arduino.cn/thread-2908-1-1.html
Lab10 使用 SHT15 溫溼度計   http://www.arduino.cn/thread-2913-1-1.html
實例介紹:只做一个Arduino温度记录器(三部曲)   http://www.arduino.cn/thread-2928-1-1.html
                                                               http://www.arduino.cn/thread-2929-1-1.html
                                                               http://www.arduino.cn/thread-2930-1-1.html
Lab11 使用 74HC595 和三支腳位控制 8 个LED   http://www.arduino.cn/thread-3006-1-1.html 
Lab12 使用兩顆 74HC595 和三支腳位控制 16个LED   http://www.arduino.cn/thread-3007-1-1.html 
Lab13 使用 74HC595 与7段数码管制作倒数功能   http://www.arduino.cn/thread-3010-1-1.html 
Lab14 使用 74HC595 控制 HD44780 兼容 LCD   http://www.arduino.cn/thread-3135-1-1.html 
Lab15 使用四位七段数码管制作计数器   http://www.arduino.cn/thread-3140-1-1.html 
Lab16 使用电位器控制舵机   http://www.arduino.cn/thread-3321-1-1.html 
Lab17 使用光敏电阻控制舵机   http://www.arduino.cn/thread-3322-1-1.html 
Lab18 讀取 3x4 Keypad 的輸入   http://www.arduino.cn/thread-3396-1-1.html
Lab19 使用 5x7 LED Matrix   http://www.arduino.cn/thread-3397-1-1.html
Lab20 用紅外線動作感測器(PIR Motion Sensor)控制 LED 的開關   http://www.arduino.cn/thread-3398-1-1.html
Lab21 用繼電器控制 12V 風扇   http://www.arduino.cn/thread-3399-1-1.html

阅读全文……

标签 : ,

java - Why is TimeZone.getTimeZone(id) synchronized, and why this isn't documented? - Stack Overflow

有JavaEE系统一个服务器实例耗尽32核CPU,看到有大量如下线程堆栈信息:

"[ACTIVE] ExecuteThread: '255' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=10 tid=0x00002aaad2ba8000 nid=0x247f waiting for monitor entry [0x00002aaaefa37000]

   java.lang.Thread.State: BLOCKED (on object monitor)

         at java.util.TimeZone.getDefaultInAppContext(TimeZone.java:627)

         - locked <0x00000006e05a43e8> (a java.lang.Class for java.util.TimeZone)

         at java.util.TimeZone.getDefaultRef(TimeZone.java:523)

         at java.util.GregorianCalendar.<init>(GregorianCalendar.java:541)

         at com.aspire.mo.framework.util.DateUtil.getCacheDate(DateUtil.java:292)

         at com.itindex.mo.framework.base.QueryTemplate$2.query(QueryTemplate.java:279)

 

上面这个锁导致了50多个线程被阻塞。

 

分析:在使用大量内存的大型多线程环境中,TimeZone是一个瓶颈,它使用了一个 synchronized HashMap

 

建议:使用Joda-Time时间类来代替Calendar类消除这个瓶颈。

 

参见下列Java 日期类性能测试:

 

// date-short:
    new Date();
//date-long: 
    new Date(year, month, date, hrs, min, sec);
// calendar:
    Calendar cal = Calendar.getInstance(TimeZone);
    cal.set(year, month, date, hourOfDay, minute, second)
    cal.getTime();
// cached-cleared-calendar:
//    Same as calendar, but with Calendar.getInstance() outside of the loop, 
//    and a cal.clear() call in the loop.

I tested single threaded performance, where 1M Dates were created using each method in a single thread. Then multi-threaded with 4 threads, each thread creating 250k Dates. In other words: both methods ended up creating the same number of Dates.

Lower is beter.
 
 

看到Calendar日期类性能最差。

 

参考:

http://blog.lick-me.org/2013/08/java-date-performance-subtleties/

http://stackoverflow.com/questions/5682236/why-is-timezone-gettimezoneid-synchronized-and-why-this-isnt-documented

 

标签 :

(8)资深内部人士:给广州各大初中重新排名——李高奇(LGQ)培优学校_西工大李高奇培优学校_新浪博客

这几年广州小升初政策年年有变花样百出
小孩赶考之复杂性简直可以用“帙繁浩叠”一词形容
众家长精疲力竭之余希望恢复小升初考试的呼声一年赛一年
在这种复杂背景之下各大初中的排位不可避免地与“我们小时候”大相径庭
不可以旧眼光旧思维去讨论
目前广州各大初中主要分成两大类:民办初中和公办初中,分成几大集团军:假定是第一集团军,第二,第三,第四。

 

民办初中,由于实行入学考试,通过考试筛选了生源,因此在这几年小升初考试中大放异彩。但是民办初中有不少是打了当年公办初中的名字,不知就里的家长很可能将两者混淆,例如以为育才实验是育才中学。
通过中考平均成绩来判断民办初中的佼佼者有:广雅实验、育才实验、中大附中、应元二中
第二集团的有:番禺华附、南武实验、祈福英语、省实天河等


而公办初中里,不少在前些年都停办了初中,仅办高中,最出名的有这几家:执信中学、广雅中学、六中。但是这两年在舆论压力和生源诱惑的双重驱动下,执信和六中已经在内部恢复小规模的初中招生。
这些年来,公办初中的佼佼者有:七中、省实、华侨外国语、广大附中、十六中、47中等。但是这类学校由于有部分是派位生源,因此总体成绩不能和民办初中最好的相比,甚至比不上民办初中第二集团,但是这些学校的重点班成绩,不比民办初中最好的差,有时甚至更好

仅以近三年成绩来论
目前广州市初中处于第一名还是华师附中
但是该初中仅在全省招收两个班共80-90人
因此不将该校成绩列入其中,仅将其当作武侠小说里“独狐求败”式的人物.

 

第一集团军:

广雅实验(民办,与广雅有关系但并非从前的广雅)、育才实验(民办,并非育才中学)、应元二中(民办,与二中有关系但并非从前的二中)、中大附中(民办,与中大附小没有直升关系,父母在中大工作子女可直接就读该校)、西关外国语(公办)、四中聚贤(非以前的四中)、六中课改班(仅招收两个班,生源基本是海珠区各校尖子生)

 

第二集团军:
民办:海珠区南武实验(非以前的南武)、海珠区珠江中学、番禺区华附(并非从前的华师附中)、番禺区祈福英语、白云区华附新世界(并非从前的华师附中)、白云区广外附设、白云区云景培英、天河区省实天河、荔湾区一中实验,

公办:花都邝中,以及越秀区的那一把名校:铁一中、省实、七中、侨外、广大附中、16中、二中、八一(八一2010年中考成绩不错,暂时先放第二集团),尤其是越秀区这一把公办的名校,重点班的成绩不比第一集团军差

第三集团:培正中学、育才中学、三中、47中,番禺东风中学,番禺侨诚中学

比培正、育才略低10-20分的,同样属于630-600分这一组的还有
汇景47中,

 

其他也还可以考虑的初中

阅读全文……

标签 :

解读广州高中学校生源的分组_2015广州中考-广州家长帮社区

下面是这届高三的全市调研考试情况表(图片来自网络)——
高三调研考试.jpg

       从上面大概可以看出,广州的高中学校是具体应该是分为六个组的,那这六个组是根据什么标准来分的呢?一直不太明白,于是只好求助网络,大概知道怎么回事——
       通常,在每年的三月下旬,市教育局会向各区教育局和学校发布《年度普通高中毕业班工作质量目标和学校生源分组情况的通知》,其中的附件之一就是学校生源的分组情况。

 

       生源分组的依据是本届毕业生当年的中考成绩,具体步骤如下:
       1、根据中考成绩确定预测参数。预测参数对应于中考分数,按照当年中考录取成绩实际情况,根据人数分布截取最高分数段和最低分数段,按10分一个分数段,划分为若干个分数段,每个分数段对应于一个预测参数,分为本科预测参数(本b)和专科(专a)预测参数。每年预测参数的确立以绝大多数学校都能达标为基点,体现激励因素。
       2、根据预测目标和规模确定生源分组。

 

       举个例,下面是2012届广州市普通高中学校生源分组情况。(文件来自教育局官网)
       根据2012年预测各校高考上省本科目标数与高三毕业班人数的百分比以及学校规模,现将2012年我市普通高中毕业班工作评价编组分为六个组,具体情况如下

组别


          


                           


  
  
  


目标≥91%,或者75目标<91%且预测本科数≥800


华师附中    省实中学    广雅中学    执信中学 广州2    广州6   秀全中学    仲元中学   番禺中学    增城中学


生源
  
二组


75目标<91%且预测本科数<800,或者65%≤目标<75%且预测本科数≥500


铁一中学     广大附中   协和中学    广州7    培正中学    广州3    广州16  广州5  天河47  真光中学  培英中学   象贤中学     从化中学


生源
  
三组


65目标<75%且预测本科数<500,或者45%≤目标<65%且预测本科数≥200,或35目标<45%且预测本科数≥300


育才中学    广州1   广州4     西关外语
  
南武中学   天河中学   省实天河学校  外贸附校   白云65  黄埔86  禺山高中  玉岩中学   维煜中学   中钧中学     增城侨中  从化6


生源
  
四组


45%≤目标<65%
  
且预测本科数<200,或35目标<45%且预测本科数<300,或24目标<35%且预测本科数≥100


广州17  广州21  中大附中  广州97    南海中学   天河75    天河89  天河113
  
东圃中学 白云80  祈福实验    东涌中学   华附番禺  石碁三中  洛城中学  大岗中学  花都实验   新华中学      南沙中学   新塘中学


  
  
  


24目标<35%且预测本科数<100,或目标<24%且预测本科数≥40


广东侨中   恒福中学   广州10   广州13  越秀外语  知用中学  广州41  海珠实验      西关培英   华美中学  白云中学  白云71   广大附实  石化中学    花都1   二师附中   鱼窝头中学  石楼中学  石碁中学   荔城中学    增城高级中学     从化5


  
  
  


目标<24%且预测本科数<40


109中学   美术中学    东环中学      广大实验
  
广州95  广州78  广州76  培才高级
  
海珠中学  北附广实    汾水中学    暨大附中   天河44   思源学校  同德南方     白云66  白云68    白云81  黄埔87   广州91
  
开发区外国语学校       园玄中学      麒麟中学   南村中学  英东中学  花都2   狮岭中学    花东中学    中大雅宝    南洋中学   从化2     从化3    从化4     英豪学校  石北中学  仙村中学  中新中学    永和中学   派潭中学  香江中学  加木纪中

    从表中可以看出,该表是根据预测目标和规模确定生源分组。具体怎么解读?
       如第一组的学校,其标准是目标≥91%,或者75目标<91%且预测本科数≥800”,也就是说,第一组学校要符合两个条件之一:高考上省本科目标数≥91;或者“75%≤ 高考上省本科目标数<91%且预测本科数≥800”
       以前一直不明白的一点是,为什么增城中学、秀全中学、番禺中学等学校,高考的重本率等参数远不如广附、铁一等,却列在一组,而其他学校却要在二组?现在明白分组也和学校的招生规模有关。如增城中学2012年高一年级招收20个班1040人;番禺中学2010年前的规模更大,招32个班(每班56人),共招1792人,2010开始将北校区命名为番禺区实验中学。番禺中学由去年招生32个班调整为20个班(每班54人),共招1080人。
       所以,学校的分组,除了和高考成绩有关,和学校的办学规模也有一定的关系。

 

       广州高中学校的分组标准是动态的,每年都不一样,2007年第一组学校的标准是目标≥80%,或者54目标<80%且预测本科数≥700”2009年第一组学校的标准是目标≥85%,或者72目标<85%且预测本科数≥500”2010年第一组学校的标准是目标≥90%,或者75目标<90%且预测本科数≥800”。随着高校的扩招,标准的逐渐提高也就在情理之中了。(目标指的是“高考上省本科目标数”

 

       对不明白的东西,我总想弄个明白,弄明白后,也总想和他人分享。虽然也许没什么作用,就当记录弄明白的过程吧。

阅读全文……

标签 :

Lucene权限实现 - 简单之美 - 企业应用与站点完美解决方案

1、权限过滤

Lucene的基于关键字的评分机制,适用于基于相关度的过滤和排序。它是基于矢量模型,其中给文档分配一个相应的分数,分数越高相关的文档也越多。然而,应用系统有时因为用户级权限仅需返回相关文档的子集。

过滤的权限问题实际上是查询时将一个布尔过滤器作用于文档的普遍问题的子问题。我们将探讨这种过滤的实现方法。

2、查询改写

上述权限过滤明显的实现方法,就是改写搜索查询为要求某字段包含特定的值。

例如,如果有一个“类别(category)”字段(Field),并假设仅显示历史(history)和科学(science)类的文档,然后对给定的用户查询:

<query>

查询可被改写为:

<query>+category:history+category:science

3、查询过滤器

此种假设对于过滤的字段(Field)可能是不适宜或不可行的(也许由于字段(Field)是易变的和频繁的变化将导致索引的大量修改)。另一方法是通过 实现Filter接口创建一个过滤器,只需实现一个方法,即bits()方法,该方法返回BitSet,包含命中的所有允许文档ID。

在bits()方法中,可使用TermEnum通过Term筛选(速度慢!),或使用FieldCache检索字段的所有值(速度快,但为内存密集型!)。

4、HitCollector + FieldCache

另一个筛选文档(Documents)的方法是使用HitCollector而非Hits对象。在collect()方法以文档(Document)ID和评分(score)作为参数,可以此来判断文档允许访问与否。

使用HitCollector有一个小缺点,Hits类中遍历搜索结果的有用方法都没有公布,但解决方法容易。

5、范例

比方说,你有一个多用户博客程序,并希望让用户搜索全部(默认)博客文章,或允许用户只搜索他发表的博客。博客应用的Lucene模型将每一博客映射为一Document。

使用查询改写方法,可以轻松地为该查询附加搜索(条件)子句:

<query>+author:<authorid>

这将只返回作者的文档。问题解决了。

现在,扩展该示例。假设在应用中存在3种访问角色:管理员(admin),编辑(editor),作家(author)。这些访问角色的权力是递减的,所 以一个编辑(editor)对作者的博客有写(write)权限,但对管理员(admin)的博客无此权限。如何才能让用户只搜索他具有写访问权限的博客 呢?

查询改写方法可用来为每一文档(Document)添加一个“角色(role)”字段(Field),并现场填入作者角色(role)。假设用户的角色为编辑(editor),那么改写后查询为:

<query>+(role:editor role:writer)

这种方法是有效的,但不是最理想的,因为每次作者的角色会改变,就需要更新他所写所有博客文档(Documents)。

另一种使用查询改写的方法是获得角色为编辑(editor)和作者(writer)的所有用户列表,然后追加到查询后,如下所示:

<query>+(author:1author:2 author:......)

这方法更好,但庞大的或-查询子句对于布尔过滤可能会妨碍搜索性能。

实现该功能的第三种方法是获取期望的用户列表,如同上前一方法,但不是改写查询,而是使用HitCollector + FieldCache的方法,因此只接受所期望的博客。这种方法具有第二种方法的优势但无性能问题。

阅读全文……

标签 : ,

performance - High load average, low CPU usage - why? - Server Fault

We're seeing huge performance problems on a web application and we're trying to find the bottleneck. I am not a sysadmin so there is some stuff I don't quite get. Some basic investigation shows the CPU to be idle, lots of memory to be available, no swapping, no I/O, but a high average load.

The software stack on this server looks like this:

. Solaris 10 . Java 1.6 . WebLogic 10.3.5 (8 domains)

The applications running on this server talk with an Oracle database on a different server.

This server has 32GB of RAM and 10 CPUs (I think).

Running prstat -Z gives something like this:

   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/NLWP

  3836 ducm0101 2119M 2074M cpu348  58    0   8:41:56 0.5% java/225

 24196 ducm0101 1974M 1910M sleep   59    0   4:04:33 0.4% java/209

  6765 ducm0102 1580M 1513M cpu330   1    0   1:21:48 0.1% java/291

 16922 ducm0102 2115M 1961M sleep   58    0   6:37:08 0.0% java/193

 18048 root     3048K 2440K sleep   59    0   0:06:02 0.0% sa_comm/4

 26619 ducm0101 2588M 2368M sleep   59    0   8:21:17 0.0% java/231

 19904 ducm0104 1713M 1390M sleep   59    0   1:15:29 0.0% java/151

 27809 ducm0102 1547M 1426M sleep   59    0   0:38:19 0.0% java/186

  2409 root       15M   11M sleep   59    0   0:00:00 0.0% pkgserv/3

 27204 root       58M   54M sleep   59    0   9:11:38 0.0% stat_daemon/1

 27256 root       12M 8312K sleep   59    0   7:16:40 0.0% kux_vmstat/1

 29367 root      297M  286M sleep   59    0  11:02:13 0.0% dsmc/2

 22128 root       13M 6768K sleep   59    0   0:10:51 0.0% sendmail/1

 22133 smmsp      13M 1144K sleep   59    0   0:01:22 0.0% sendmail/1

 22003 root     5896K  240K sleep   59    0   0:00:01 0.0% automountd/2

 22074 root     4776K 1992K sleep   59    0   0:00:19 0.0% sshd/1

 22005 root     6184K 2728K sleep   59    0   0:00:31 0.0% automountd/2

 27201 root     6248K  344K sleep   59    0   0:00:01 0.0% mount_stat/1

 20964 root     2912K  160K sleep   59    0   0:00:01 0.0% ttymon/1

 20947 root     1784K  864K sleep   59    0   0:02:22 0.0% utmpd/1

 20900 root     3048K  608K sleep   59    0   0:00:03 0.0% ttymon/1

 20979 root       77M   18M sleep   59    0   0:14:13 0.0% inetd/4

 20849 daemon   2856K  864K sleep   59    0   0:00:03 0.0% lockd/2

 17794 root       80M 1232K sleep   59    0   0:06:19 0.0% svc.startd/12

 17645 root     3080K  728K sleep   59    0   0:00:12 0.0% init/1

 17849 root       13M 6800K sleep   59    0   0:13:04 0.0% svc.configd/15

 20213 root       84M   81M sleep   59    0   0:47:17 0.0% nscd/46

 20871 root     2568K  600K sleep   59    0   0:00:04 0.0% sac/1

  3683 ducm0101 1904K 1640K sleep   56    0   0:00:00 0.0% startWebLogic.s/1

 23937 ducm0101 1904K 1640K sleep   59    0   0:00:00 0.0% startWebLogic.s/1

 20766 daemon   5328K 1536K sleep   59    0   0:00:36 0.0% nfsmapid/3

 20141 daemon   5968K 3520K sleep   59    0   0:01:14 0.0% kcfd/4

 20093 ducm0101 2000K  376K sleep   59    0   0:00:01 0.0% pfksh/1

 20797 daemon   3256K  240K sleep   59    0   0:00:01 0.0% statd/1

  6181 root     4864K 2872K sleep   59    0   0:01:34 0.0% syslogd/17

  7220 ducm0104 1268M 1101M sleep   59    0   0:36:35 0.0% java/138

 27597 ducm0102 1904K 1640K sleep   59    0   0:00:00 0.0% startWebLogic.s/1

 27867 root       37M 4568K sleep   59    0   0:13:56 0.0% kcawd/7

 12685 ducm0101 4080K  208K sleep   59    0   0:00:01 0.0% vncconfig/1

ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE

    42      135   22G   19G    59%  87:27:59 1.2% dsuniucm01

 

Total: 135 processes, 3167 lwps, load averages: 54.48, 62.50, 63.11

I understand that CPU is mostly idle, but the load average is high, which is quite strange to me. Memory doesn't seem to be a problem.

Running vmstat 15 gives something like this:

 kthr      memory            page            disk          faults      cpu

 r b w   swap  free  re  mf pi po fr de sr s0 s1 s4 sd   in   sy   cs us sy id

 0 0 0 32531400 105702272 317 1052 126 0 0 0 0 13 13 -0 8 9602 107680 10964 1 1 98

 0 0 0 15053368 95930224 411 2323 0 0 0 0 0 0  0  0  0 23207 47679 29958 3 2 95

 0 0 0 14498568 95801960 3072 3583 0 2 2 0 0 3 3  0 21 22648 66367 28587 4 4 92

 0 0 0 14343008 95656752 3080 2857 0 0 0 0 0 3 3  0 18 22338 44374 29085 3 4 94

 0 0 0 14646016 95485472 1726 3306 0 0 0 0 0 0 0  0  0 24702 47499 33034 3 3 94

I understand that the CPU is mostly idle, no processes are waiting in the queue to be executed, little swapping is happening.

Running iostat 15 gives this:

   tty        sd0           sd1           sd4           ssd0           cpu

 tin tout kps tps serv  kps tps serv  kps tps serv  kps tps serv   us sy wt id

   0  676 324  13    8  322  13    8    0   0    0  159   8    0    1  1  0 98

   1 1385   0   0    0    0   0    0    0   0    0    0   0    0    3  4  0 94

   0  584  89   6   24   89   6   25    0   0    0  332  19    0    2  1  0 97

   0  296   0   0    0    0   0    0    0   0    0    0   0    0    2  2  0 97

   1 1290  43   5   24   43   5   22    0   0    0  297  20    1    3  3  0 94

Running netstat -i 15 gives the following:

    input   aggr26    output       input  (Total)    output
packets errs  packets errs  colls  packets errs  packets errs  colls
1500233798 0     1489316495 0     0      3608008314 0     3586173708 0     0
10646   0     10234   0     0      26206   0     25382   0     0
11227   0     10670   0     0      28562   0     27448   0     0
10353   0     9998    0     0      29117   0     28418   0     0
11443   0     12003   0     0      30385   0     31494   0     0
 

When you say 'High Load average' I assume you mean that prstat shows for 'load average' at the bottom of the output figures of

Total: 135 processes, 3167 lwps, load averages: 54.48, 62.50, 63.11

These numbers, look similar to the ones that top provides and probably mean the average queue size of running process. This isn't the percentage of processor time being used but how many 'things' are harassing the CPU for time to run. Admittedly, these do look quite high but this all depends on the app that you are running; the processes may not actually be doing much once they get their slot. See herefor a nice explanation regarding top.

I'm not familiar with WebLogic but I have noticed that, generally, with Apache Tomcat many Java threads can be spawned simultaneously for what appears as not many requests. It could be this that is causing those high average load numbers. Make sure that you are using connection pooling where appropriate to connect to the backend and consider upping the number of idle threads that are available to your app to handle connections (not sure how you do this on WebLogic; Tomcat has a per connector thread pool or a general executor thread pool). If you don't do this then brand new threads may be being spawned to process requests.

As to performance, you need to nail down what part of your app is suffering. Is it the processing that is happening in the WebLogic/Java side of things, the database access, DNS lookups (if they're being done for some reason...), network issues or something on the OS.

99% of the time it will be your code and how it talks to the database that is holding things up. Then it will be configuration of the web app. Past this point you will be working on squeezing the last milliseconds out of your app or looking at providing higher concurrency with the same hardware. For this finer grained performance tuning you need metrics.

For Java I'd suggest installing Java Melody. It can provide a lot of info regarding what your program is doing and help narrow down where it is spending time. I've only used it with Tomcat but should work fine with any Java EE container/servlet thingy.

There are a number of ways you can tune Java, so take a look at their performance guidelines (I'm sure you probably have) and make sure you're setting the correct Heap Size etc. suitable for your program. Java Melody can help you track down the size of Java's heap you're consuming as well as how hard the garbage collector is working/how often it is interrupting your program to clear objects.

I hope that has been helpful. If you provide any more information, I may be able to update this answer and hone it more towards your needs.

 

With some further investigation, it appears that the performance problem is mostly due to a high number of network calls between two systems (Oracle SSXA and UCM). The calls are quick but plenty and serialized, hence the low CPU usage (mostly waiting for I/O), the high load average (many calls waiting to be processed) and especially the long response times (by accumulation of small response times).

 

(2) how to understand the load average on the first line ("load average: 14.04, 14.02, 14.00")?

This article on load average uses a nice traffic analogy and is the best one I've found so far:Understanding Linux CPU Load - when should you be worried?. In your case, as people pointed out:

On multi-processor system, the load is relative to the number of processor cores available. The "100% utilization" mark is 1.00 on a single-core system, 2.00, on a dual-core, 4.00 on a quad-core, etc.

So, with a load average of 14.00 and 24 cores, your server is far from being overloaded.

 

参考:

http://www.linuxjournal.com/article/9001

http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages

 

阅读全文……

标签 : ,

[ lucene扩展 ] spellChecker原理分析 - MR-fox - 博客园

lucene中spellchecker简述

lucene 的扩展包中包含了spellchecker,利用它我们可以方便的实现拼写检查的功能,但是检查的效果(推荐的准确程度)需要开发者进行调整、优化。

 

lucene实现“拼写检查”的步骤

步骤1:建立spellchecker所需的索引文件

spellchecker也需要借助lucene的索引实现的,只不过其采用了特殊的分词方式和相关度计算方式。

建立spellchecker所需的索引文件可以用文本文件提供内容,一行一个词组,类似于字典结构。

例如(dic.txt):

麻辣烫
中文测试
麻辣酱
麻辣火锅
中国人
中华人民共和国

建立spellchecker索引的关键代码如下:

     /**
 * 根据字典文件创建spellchecker所使用的索引。
 *
 * @param spellIndexPath
 *            spellchecker索引文件路径
 * @param idcFilePath
 *            原始字典文件路径
 * @throws IOException
 */
public void createSpellIndex(String spellIndexPath, String idcFilePath)
        throws IOException {
    Directory spellIndexDir = FSDirectory.open(new File(spellIndexPath));
    SpellChecker spellChecker = new SpellChecker(spellIndexDir);
    IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,
            null);
    spellChecker.indexDictionary(new PlainTextDictionary(new File(
            idcFilePath)), config, false);
    // close
    spellIndexDir.close();
    spellChecker.close();
}

这里使用了PlainTextDictionary对象,他实现了Dictionary接口,类结构如下图所示:

除了PlainTextDictionary(1 word per line),我们还可以使用:

  • FileDictionary(1 string per line, optionally with a tab-separated integer value | 词组之间用tab分隔)
  • LuceneDictionary(Lucene Dictionary: terms taken from the given field of a Lucene index | 用现有的index的term建立索引)
  • HighFrequencyDictionary(HighFrequencyDictionary: terms taken from the given field of a Lucene index, which appear in a number of documents above a given threshold. | 在LuceneDictionary的基础上加入了一定的限定,term只有出现在各document中的次数满足一定数量时才被spellchecker采用)

例如我们采用luceneDictionary,主要代码如下:

/**
 * 根据指定索引中的字典创建spellchecker所使用的索引。
 *
 * @param oriIndexPath
 *            指定原始索引
 * @param fieldName
 *            索引字段(某个字段的字典)
 * @param spellIndexPath
 *            原始字典文件路径
 * @throws IOException
 */
public void createSpellIndex(String oriIndexPath, String fieldName,
        String spellIndexPath) throws IOException {
    IndexReader oriIndex = IndexReader.open(FSDirectory.open(new File(
            oriIndexPath)));
    LuceneDictionary dict = new LuceneDictionary(oriIndex, fieldName);
    Directory spellIndexDir = FSDirectory.open(new File(spellIndexPath));
    SpellChecker spellChecker = new SpellChecker(spellIndexDir);
    IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,
            null);
    spellChecker.indexDictionary(dict, config, true);
}

我们对dic.txt建立索引后,可以对其内部文档和term进行进一步了解,如下:

Document<stored,indexed,omitNorms,indexOptions=DOCS_ONLY<word:麻辣烫>>
Document<stored,indexed,omitNorms,indexOptions=DOCS_ONLY<word:中文测试>>
Document<stored,indexed,omitNorms,indexOptions=DOCS_ONLY<word:麻辣酱>>
Document<stored,indexed,omitNorms,indexOptions=DOCS_ONLY<word:麻辣火锅>>
Document<stored,indexed,omitNorms,indexOptions=DOCS_ONLY<word:中国人>>
Document<stored,indexed,omitNorms,indexOptions=DOCS_ONLY<word:中华人民共和国>>
end1:人 
end1:烫  end1:试  end1:酱  end1:锅  end2:国人 end2:测试 end2:火锅 end2:辣烫 end2:辣酱 end3:共和国   
end4:民共和国   gram1:中 gram1:人 gram1:国 gram1:文 gram1:测 gram1:火 gram1:烫 gram1:试 gram1:辣
gram1:酱 gram1:锅 gram1:麻 gram1:  gram2:中国    gram2:中文    gram2:国人    gram2:文测    gram2:测试    gram2:火锅   
gram2:辣火    gram2:辣烫    gram2:辣酱    gram2:麻辣    gram2:麻 gram3:中华人   gram3:人民共   gram3:共和国   gram3:华人民   gram3:民共和  
gram4:中华人民  gram4:人民共和  gram4:华人民共  gram4:民共和国  start1:中    start1:麻    start1: start2:中国   start2:中文   start2:麻辣  
start2:麻    start3:中华人  start4:中华人民 word:中华人民共和国    word:中国人    word:中文测试   word:麻辣火锅   word:麻辣酱    word:麻辣烫   

可以看出,每一个词组(dic.txt每一行的内容)被当成一个document,然后采用特殊的分词方式对其进行分词,我们可以看出field的名称比较奇怪,例如:end1,end2,gram1,gram2等等。

为什么这么做,什么原理?我们先留下这个疑问,看完效果后再说明!

 

步骤二:spellchecker的“检查建议”

我们使用第一步创建的索引,利用spellChecker.suggestSimilar方法进行拼写检查。全部代码如下:

package com.fox.lab;
 
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
 
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.spell.LuceneDictionary;
import org.apache.lucene.search.spell.SpellChecker;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
 
/**
 * @author huangfox
 * @createDate 2012-2-16
 */
public class DidYouMeanSearcher {
    SpellChecker spellChecker = null;
    LuceneDictionary dict = null;
 
    /**
     *
     * @param spellCheckIndexPath
     *            spellChecker索引位置
     */
    public DidYouMeanSearcher(String spellCheckIndexPath, String oriIndexPath,
            String fieldName) {
        Directory directory;
        try {
            directory = FSDirectory.open(new File(spellCheckIndexPath));
            spellChecker = new SpellChecker(directory);
            IndexReader oriIndex = IndexReader.open(FSDirectory.open(new File(
                    oriIndexPath)));
            dict = new LuceneDictionary(oriIndex, fieldName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 设定精度,默认0.5
     *
     * @param v
     */
    public void setAccuracy(float v) {
        spellChecker.setAccuracy(v);
    }
 
    /**
     * 针对检索式进行spell check
     *
     * @param queryString
     *            检索式
     * @param suggestionsNumber
     *            推荐的最大数量
     * @return
     */
    public String[] search(String queryString, int suggestionsNumber) {
        String[] suggestions = null;
        try {
            // if (exist(queryString))
            // return null;
            suggestions = spellChecker.suggestSimilar(queryString,
                    suggestionsNumber);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return suggestions;
    }
 
    private boolean exist(String queryString) {
        Iterator<String> ite = dict.getWordsIterator();
        while (ite.hasNext()) {
            if (ite.next().equals(queryString))
                return true;
        }
        return false;
    }
}

测试效果:

package com.fox.lab;
 
import java.io.IOException;
 
public class DidYouMeanMainApp {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // 创建index
        DidYouMeanIndexer indexer = new DidYouMeanIndexer();
        String spellIndexPath = "D:\\spellchecker";
        String idcFilePath = "D:\\dic.txt";
        String oriIndexPath = "D:\\solrHome\\example\\solr\\data\\index";
        String fieldName = "ab";
        DidYouMeanSearcher searcher = new DidYouMeanSearcher(spellIndexPath,
                oriIndexPath, fieldName);
        searcher.setAccuracy(0.5f);
        int suggestionsNumber = 15;
        String queryString = "麻辣将";
//      try {
//          indexer.createSpellIndex(spellIndexPath, idcFilePath);
        // indexer.createSpellIndex(oriIndexPath, fieldName, spellIndexPath);
        // } catch (IOException e) {
        // e.printStackTrace();
        // }
        String[] result = searcher.search(queryString, suggestionsNumber);
        if (result == null || result.length == 0) {
            System.out.println("我不知道你要什么,或许你就是对的!");
        } else {
            System.out.println("你是不是想找:");
            for (int i = 0; i < result.length; i++) {
                System.out.println(result[i]);
            }
        }
    }
 
}

输出:

你是不是想找:
麻辣酱
麻辣火锅
麻辣烫

将queryString改为“中文测式”,输出:

你是不是想找:
中文测试

当输入正确时,例如“中文测试”,则输出:

我不知道你要什么,或许你就是对的!

 


拼写检查的基本功能实现了,虽然还存在很多问题需要改进调整。我们先来了解其中两个基本原理。

第一原理:N-gram

我们要实现spellchecker,其实简单理解就是将用户输入的词组(英文为单词,中文为词组)和字典里面“标准”的词组进行“相似性”比较,并给出相似程度最高的词组。

那么如何比较两个字符串的相似程度就是spellchecker的关键所在。

字符串P 的N-gram 是P 中任意长度为N 的子串。例如,单词waist 的Bigram 有wa、ai、is 和st 四个。对于给定的字符串P 和W,其N-gram 相似度gram-count(P,W) 定义为同时在P 和W 中出现的N-gram 数目。在lucene的spellchecker中对N-gram进行了扩展,对整个单词、单词的头尾都做了处理,例如:麻辣烤翅,分解成:

start2:麻   
start3:麻辣
 
end2:烤翅
end3:辣烤翅
 
gram2:烤翅   
gram2:辣烤   
gram2:麻辣   
gram2:麻
 
gram3:辣烤翅  
gram3:麻辣烤  
gram3:麻辣   
 
word:麻辣烤翅  

当用户输入“麻辣靠翅”时,被分解成:

end2:靠翅 end3:辣靠翅 gram2:靠翅 gram2:辣靠 gram2:麻辣 gram2:麻 gram3:辣靠翅 gram3:麻辣靠 gram3:麻辣 start2:麻 start3:麻辣 word:麻辣靠翅

并将这些term组成一个用OR连接的检索式(不同的term可能赋予不同的权重),在spellchecker的索引里进行检索,即可匹配到文档“麻辣烤翅”。但是不是就要把它推荐(suggest)出来呢?还要看他们的相识度是否符合要求。在lucene的spellchecker中,默认相似度为0.5。

lucene——spellchecker的n-gram分词算法如下:

private static void addGram(String text, Document doc, int ng1, int ng2) {
  int len = text.length();
  for (int ng = ng1; ng <= ng2; ng++) {
    String key = "gram" + ng;
    String end = null;
    for (int i = 0; i < len - ng + 1; i++) {
      String gram = text.substring(i, i + ng);
      Field ngramField = new Field(key, gram, Field.Store.NO, Field.Index.NOT_ANALYZED);
      // spellchecker does not use positional queries, but we want freqs
      // for scoring these multivalued n-gram fields.
      ngramField.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
      doc.add(ngramField);
      if (i == 0) {
        // only one term possible in the startXXField, TF/pos and norms aren't needed.
        Field startField = new Field("start" + ng, gram, Field.Store.NO, Field.Index.NOT_ANALYZED);
        startField.setIndexOptions(IndexOptions.DOCS_ONLY);
        startField.setOmitNorms(true);
        doc.add(startField);
      }
      end = gram;
    }
    if (end != null) { // may not be present if len==ng1
      // only one term possible in the endXXField, TF/pos and norms aren't needed.
      Field endField = new Field("end" + ng, end, Field.Store.NO, Field.Index.NOT_ANALYZED);
      endField.setIndexOptions(IndexOptions.DOCS_ONLY);
      endField.setOmitNorms(true);
      doc.add(endField);
    }
  }
}

  

 

第二原理:相似度计算(stringDistance)

在lucene的spellchecker中,StringDistance作为接口,有三个实现类,如下:

  • JaroWinklerDistance
  • LevensteinDistance
  • NGramDistance

我们这里采用LevensteinDistance进行字符串相似度计算。LevensteinDistance就是edit distance(编辑距离)。

编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

例如将kitten一字转成sitting:

  sitten (k→s) 

  sittin (e→i) 

  sitting (→g) 

  俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。

lucene中算法如下:

public float getDistance (String target, String other) {
      char[] sa;
      int n;
      int p[]; //'previous' cost array, horizontally
      int d[]; // cost array, horizontally
      int _d[]; //placeholder to assist in swapping p and d
       
        /*
           The difference between this impl. and the previous is that, rather
           than creating and retaining a matrix of size s.length()+1 by t.length()+1,
           we maintain two single-dimensional arrays of length s.length()+1.  The first, d,
           is the 'current working' distance array that maintains the newest distance cost
           counts as we iterate through the characters of String s.  Each time we increment
           the index of String t we are comparing, d is copied to p, the second int[].  Doing so
           allows us to retain the previous cost counts as required by the algorithm (taking
           the minimum of the cost count to the left, up one, and diagonally up and to the left
           of the current cost count being calculated).  (Note that the arrays aren't really
           copied anymore, just switched...this is clearly much better than cloning an array
           or doing a System.arraycopy() each time  through the outer loop.)
 
           Effectively, the difference between the two implementations is this one does not
           cause an out of memory condition when calculating the LD over two very large strings.
         */
 
        sa = target.toCharArray();
        n = sa.length;
        p = new int[n+1];
        d = new int[n+1];
       
        final int m = other.length();
        if (n == 0 || m == 0) {
          if (n == m) {
            return 1;
          }
          else {
            return 0;
          }
        }
 
 
        // indexes into strings s and t
        int i; // iterates through s
        int j; // iterates through t
 
        char t_j; // jth character of t
 
        int cost; // cost
 
        for (i = 0; i<=n; i++) {
            p[i] = i;
        }
 
        for (j = 1; j<=m; j++) {
            t_j = other.charAt(j-1);
            d[0] = j;
 
            for (i=1; i<=n; i++) {
                cost = sa[i-1]==t_j ? 0 : 1;
                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
                d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1),  p[i-1]+cost);
            }
 
            // copy current distance counts to 'previous row' distance counts
            _d = p;
            p = d;
            d = _d;
        }
 
        // our last action in the above loop was to switch d and p, so p now
        // actually has the most recent cost counts
        return 1.0f - ((float) p[n] / Math.max(other.length(), sa.length));
    }

  

 


 

 需要改进的地方

1.精度不高,特别是对于两个字的词组。可以在距离计算(相似度计算)方面进行调整。

2.没有拼音的功能,例如麻辣kao翅,将无法进行校正。

3.对于字符串中出现的错误无法进行校正,例如“常州哪里有卖变态麻辣靠翅”。

 

阅读全文……

标签 : ,