CentOS自己编译安装Python3的命令

yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel

 

参照:https://blog.51cto.com/13544424/2149473

解决缺少SSL问题(安装1.1.1版本),然后往下走

 

./configure prefix=/usr/local/python3 –with-openssl=/usr/local/openssl

make && make install

/usr/local/python3/bin/python3 -m pip install –upgrade pip

/usr/local/python3/bin/python3 -m pip install redis

数据处理中提升性能的方法-引入并发但是避免同步

背景

只要存在数据库,就会有后台批量处理数据的需求,比如数据表备份、定期清理、数据替换、数据迁移,对于批量处理来说,往往会涉及大量的查询、过滤、归类、聚合计算,在批量脚本中直接查询数据库往往性能太低,甚至会因为一个大型的SQL导致数据库锁表出现线上事故,因此一般采用先导出到文件,在文件上计算然后再导入,比如:

1、使用mysql -e “select * from table” > output.txt的方式,执行SQL,将结果导出到文件中;

2、针对文件,使用各种方式进行聚合、过滤、替换等计算,最后产出成需要使用的格式;

3、发布产出的文件,或者使用load data命令导入到数据库;

由于只是一次性的批量查询数据库导出到文件,然后针对文件进行计算,而不是每次都查询数据库,大量节省了网络的IO耗费,从而提升处理的速度。

然而得到了导出的文件之后,如果文件过大,或者计算逻辑复杂比如大量的调用了耗费CPU的正则匹配、聚合计算,那么单线程的处理会耗费大量的时间,这时候就可以引入并发处理,使得机器的CPU、内存、IO、网络等资源全部充分利用起来,大幅度降低处理时间。

引入多线程,拆分输入文件为多个,每个小文件启动一个处理线程

HADOOP的MAP-REDUCE的做法,是先将文件split成小分片文件,然后针对每个分片做计算,最后将每个分片的结果聚合在一起,然而由于HADOOP的调度、集群稳定性等各种原因,对于MB大小级别的文件处理,会发现速度非常慢,有时候甚至比单机单线程处理速度还慢,将单机单线程改成多线程,往往会发现令人惊讶的效果提升。

直观的做法,是使用主线程读取输入的单个大文件,然后将读取的结果分配给子线程处理,然后主线程做整合,这种方式因为多线程共用了单个文件的IO,需要加入对文件的同步机制,最后会发现性能瓶颈在这单个文件的读取同步之上。

可以将大文件分片成小文件,然后每个文件分配给单个线程单独处理,避免线程间的资源同步,每个线程会享用单独的CPU核、内存单元、文件句柄,处理速度能达到最快。

使用这种方式,可以用以下的步骤进行:

1、使用SHELL,将输入文件拆分成预定线程数目的份数,存放到一个目录中;

2、以输入文件的目录路径作为参数,编程语言JAVA/PYTHON读取该目录的所有文件,对于每个文件启动一个处理线程,进行处理;

3、SHELL将输出目录的所有文件,使用cat file* > output_file的方式,得到最终的计算结果

#
# 将输入文件拆分成多个小文件,启动多线程进行处理,输出结果文件
#
function run_multi_task(){
	# 开启多个异步线程
	SPLITS_COUNT=20
	# 输入文件总数
	source_file_lines_count=`cat ${input_file} | wc -l`
	# 计算出拆分的文件个数
	split_file_lines_count=$(( $source_file_lines_count / $SPLITS_COUNT ))
	# 进行文件拆分
	split -l $split_file_lines_count -a 3 -d ${input_file} ${input_dir}/inputFile_
	
	# 执行JAVA程序
	$JAVA_CMD -classpath $jar_path "net.crazyant.BackTaskMain" "${input_dir}" "${output_dir}" "${output_err_dir}"
	
	# 合并文件
	cat ${output_dir}/* > ${output_file}
}

run_multi_task

这里注意,拆分文件的时候,不能使用split按照大小进行拆分,因为会把输入文件中的行截断;

对应的JAVA程序,则是通过读取文件夹中文件列表的方法,每个文件单独启动一个线程:

public class BackTaskMain {
    public static void main(String[] args) {
        String inputDataDir = args[1];
        String outputDataDir = args[2];
        String errDataDir = args[3];
        
        File inputDir = new File(inputDataDir);
        File[] inputFiles = inputDir.listFiles();
        
        // 记录开启的线程
        List<Thread> threads = new ArrayList<Thread>();
        for (File inputFile : inputFiles) {
            if (inputFile.getName().equals(".") || inputFile.getName().equals("..")) {
                continue;
            }
            
            // 针对每个inputFile,生成对应的outputFile和errFile
            String outputSrcLiceFpath = outputDataDir + "/" + inputFile.getName() + ".out";
            String errorOutputFpath = errDataDir + "/" + inputFile.getName() + ".err";
            
            // 创建Runnable
            BackRzInterface backRzInterface = new BackRzInterface();
            backRzInterface.setInputFilePath(inputFile.getAbsolutePath());
            backRzInterface.setOutputFilePath(outputSrcLiceFpath);
            backRzInterface.setErrorOutputFpath(errorOutputFpath);
            
            // 创建Thread,启动线程
            Thread singleRunThread = new Thread(backRzInterface);
            threads.add(singleRunThread);
            singleRunThread.start();
        }
        
        for (Thread thread : threads) {
            try {
                // 使用thread.join(),等待所有的线程执行完毕
                thread.join();
                System.out.println(thread.getName() + " has over");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("proccess all over");
    }
}

通过这种方式,将大文件拆分成小文件,启动多个线程,每个线程处理一个小文件,最终将每个小文件的结果聚合,就得到了最终产出,性能上却大幅提升。

若有依赖的资源,可以按线程先复制、拆分、克隆,防止依赖的资源成为性能瓶颈

在上面的代码中,BackRzInterface是每个线程启动时要使用的Runnable对象,可以看到用的是每次new的方式创建:

// 创建Runnable
BackRzInterface backRzInterface = new BackRzInterface();

这样每个处理线程依赖的BackRzInterface都是独立的,对这个Runnable代码的使用不会存在同步问题。

如果多线程处理中需要使用外部资源,最好想办法使得每个线程单独使用自己独占的资源,相互之间若不会存在冲突,可以实现最大化并发处理。

其他一些例子,比如:

  • 多线程用到了字典文件,那么方法是首先将字典文件复制多份,每个线程使用自己独占的字典,避免并发同步访问字典;
  • 多线程若需要统一ID发号,可以提前计算出每个输入文件的行数,然后依次生成第一个线程需要的ID范围、第二个线程需要的ID范围,这些不同的ID范围也可以分别生成不同的文件,这样每个线程会使用各自独立的ID资源,避免了多个线程单时刻访问单个ID发号服务,使得发号成为性能瓶颈的可能;
  • 多线程如果依赖相同的Service,如果可以每次new对象就每次new,如果Bean都是在Spring中管理,则将Service加上@Scope(“prototype”),或者将对象每次clone一下得到一个新对象,保证最终每个线程使用自己独占的对象。
  • 尽量使用函数式编程的思想,每个函数都不要产生副作用,不要修改入参,结果只能通过return返回,避免增加代码同步冲突的可能;

通过以上这些类似的方法,每次将可能需要同步访问的共享资源,通过复制、分片等手段得到不同份,每个线程单独访问自己那一份,避免同步访问,最终实现性能最优。

避免同步的终极方法:使用多进程进行实现资源隔离

如果将文件拆分成了多份,依赖的ID、词典等资源也相应提供了多份,但是发现代码中存在无法解决的代码级别同步,该怎么办呢?

相对于想尽办法解决代码中的同步问题来说,多线程和多进程之间的性能差别微乎其微,我们都知道线程会使用进程的资源,所以导致了线程之间存在竞争进程资源,但是对于进程来说,CPU、内存等硬件资源是完全隔离的,这时候将程序运行在多进程而不是多线程,反而能更好的提升性能。

对于一些支持多线程不好的语言,比如PHP,直接用这种多进程计算的方法,速度并不比支持多线程的JAVA、PYTHON语言差:

# 要拆分的文件数,也就是要启动的多进程数
SPLITS_COUNT=20

input_splits_dir="${input_dir}_splits"
output_splits_dir="${output_dir}_splits"
# 输入文件行数
source_file_lines_count=`cat ${input_file} | wc -l`
# 每个文件拆分的行数=总行数除以要拆分的文件个数(也就是对应进程的个数)
split_file_lines_count=$(( $source_file_lines_count / ${SPLITS_COUNT} ))
# 执行拆分,注意这里使用-l进行行级别拆分更好
split -l $split_file_lines_count -a 3 -d ${input_file} ${input_splits_dir}/inputfile_

process_idx=1
for fname in $(ls ${input_splits_dir}); do
	input_fpath=${input_splits_dir}/$fname
	ouput_fpath=${output_splits_dir}/$fname
	# 后台执行所有进程
	php "/php/main.php" "${input_fpath}" "${ouput_fpath}" &
	(( process_idx++ ))	
done

# 等待所有后台进程执行结束
wait

# 合并文件
cat $output_splits_dir/* > ${output_file}

上述代码中,使用shell的&符号,可以在后台同时启动多个进程,使用wait语法,可以实现多线程的Thread.join特性,等待所有的进程执行结束。

总结

对于输入文件的大小、计算的复杂度处于单机和集群计算之间的数据处理,使用并发处理最为合适,但是并发的同步处理却会降低多线程的性能,这时可以借助于输入文件复制拆分、依赖资源复制拆分切片等方法,实现每个线程处理自己的独占资源,从而最大化提升计算速度。而对于一些无法避免的代码同步冲突逻辑,可以退化为多进程处理数据,借助于SHELL的后台进程支持,实现进程级别的资源独占,最终大幅提升处理性能。

 

Bash Shell怎样检查文件是否存在?

在类Unix系统的Bash环境下,怎样检查文件是否存在呢?

Shell中的test命令,可以用来检测文件的类型或者比较数值是否相等,该命令也能用来检查文件是否存在。

可以用如下的命令来进行检查:

test -e filename
[ -e filename ]
 
test -f filename
[ -f filename ]

下面的命令,则使用Shell的条件表达式,判断/etc/hosts文件是否存在:

[ -f /etc/hosts ] && echo "Found" || echo "Not found"

该组合命令会输出以下内容:

Found

更常见的用法,则是将test命令放置在if..else..fi条件判断的条件表达式,然后在其中写上不同的分支逻辑

#!/bin/bash
file="/etc/hosts"
if [ -f "$file" ]
then
	echo "$file found."
else
	echo "$file not found."
fi

检测文件属性的相关操作符

如果文件存在,并且具有相应的属性,如下的操作符都会返回true:

       -b FILE
              FILE exists and is block special
       -c FILE
              FILE exists and is character special
       -d FILE
              FILE exists and is a directory
       -e FILE
              FILE exists
       -f FILE
              FILE exists and is a regular file
       -g FILE
              FILE exists and is set-group-ID
       -G FILE
              FILE exists and is owned by the effective group ID
       -h FILE
              FILE exists and is a symbolic link (same as -L)
       -k FILE
              FILE exists and has its sticky bit set
       -L FILE
              FILE exists and is a symbolic link (same as -h)
       -O FILE
              FILE exists and is owned by the effective user ID
       -p FILE
              FILE exists and is a named pipe
       -r FILE
              FILE exists and read permission is granted
       -s FILE
              FILE exists and has a size greater than zero
       -S FILE
              FILE exists and is a socket
       -t FD  file descriptor FD is opened on a terminal
       -u FILE
              FILE exists and its set-user-ID bit is set
       -w FILE
              FILE exists and write permission is granted
       -x FILE
              FILE exists and execute (or search) permission is granted

以上命令,从man test复制而来。

使用上述符号的方法一模一样:

if [ operator FileName ]
then
     echo "FileName - Found, take some action here"
else
   echo "FileName - Not found, take some action here"
fi

文章翻译自:http://www.cyberciti.biz/faq/unix-linux-test-existence-of-file-in-bash/

本文地址:http://crazyant.net/1895.html,转载请注明来源。

python执行shell的两种方法

有两种方法可以在Python中执行SHELL程序,方法一是使用Python的commands包,方法二则是使用subprocess包,这两个包均是Python现有的内置模块。

使用python内置commands模块执行shell

commands对Python的os.popen()进行了封装,使用SHELL命令字符串作为其参数,返回命令的结果数据以及命令执行的状态;

该命令目前已经废弃,被subprocess所替代;

# coding=utf-8
'''
Created on 2013年11月22日

@author: crazyant.net
'''
import commands
import pprint

def cmd_exe(cmd_String):
    print "will exe cmd,cmd:"+cmd_String
    return commands.getstatusoutput(cmd_String)

if __name__=="__main__":
    pprint.pprint(cmd_exe("ls -la"))

使用python最新的subprocess模块执行shell

Python目前已经废弃了os.system,os.spawn*,os.popen*,popen2.*,commands.*来执行其他语言的命令,subprocesss是被推荐的方法

subprocess允许你能创建很多子进程,创建的时候能指定子进程和子进程的输入、输出、错误输出管道,执行后能获取输出结果和执行状态。

# coding=utf-8
'''
Created on 2013年11月22日

@author: crazyant.net
'''
import shlex
import datetime
import subprocess
import time

def execute_command(cmdstring, cwd=None, timeout=None, shell=False):
    """执行一个SHELL命令
            封装了subprocess的Popen方法, 支持超时判断,支持读取stdout和stderr
           参数:
        cwd: 运行命令时更改路径,如果被设定,子进程会直接先更改当前路径到cwd
        timeout: 超时时间,秒,支持小数,精度0.1秒
        shell: 是否通过shell运行
    Returns: return_code
    Raises:  Exception: 执行超时
    """
    if shell:
        cmdstring_list = cmdstring
    else:
        cmdstring_list = shlex.split(cmdstring)
    if timeout:
        end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
    
    #没有指定标准输出和错误输出的管道,因此会打印到屏幕上;
    sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096)
    
    #subprocess.poll()方法:检查子进程是否结束了,如果结束了,设定并返回码,放在subprocess.returncode变量中 
    while sub.poll() is None:
        time.sleep(0.1)
        if timeout:
            if end_time <= datetime.datetime.now():
                raise Exception("Timeout:%s"%cmdstring)
            
    return str(sub.returncode)

if __name__=="__main__":
    print execute_command("ls")

也可以在Popen中指定stdin和stdout为一个变量,这样就能直接接收该输出变量值。

总结

在python中执行SHELL有时候也是很必须的,比如使用Python的线程机制启动不同的shell进程,目前subprocess是Python官方推荐的方法,其支持的功能也是最多的,推荐大家使用。

转载请注明来源:http://crazyant.net/1319.html

shell/hadoop/hive一些有用命令收集

有些命令工作中经常用到,记录在一个文章里用于查阅,本文经常更新。

shell命令

linux统计某个目录下所有文件的行数的命令
find /home/crazyant -type f -name "*" | xargs cat | wc -l

用find查找crazyant目录下所有文本文件的行数之和。不过该命令执行挺慢的。

linux统计某个目录下所有目录和总目录的大小命令
du -h --max-depth=1 /home/crazyant/

统计crazyant目录下的所有文件的大小,这里我只想看到一层目录的大小,因此加上了—max-depth=1如果不加这个参数,该命令会以递归的方式列出所有子目录的文件大小

scp命令的使用:

从本地复制到远程:scp -r  logs_jx pss@crazyant.net/home/pss/logs

hive命令

hive建立和执行索引
create index table02_index on table table02(id) as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' with deferred rebuild; 
alter index table02_index on table02 rebuild;

第一句hive在表上建立了索引但没有生效,第二句真正的执行建立索引的过程,其本身也是一个map –reduce过程。

hive的Load data命令
hive -e "
	use crazyant_net; 
	LOAD DATA INPATH '/app/crazyant/student/*' INTO TABLE student;"

其中inpath的意思是input path的意思,所以不管是从本地local还是hdfs上load data,都要带上。

 

hadoop命令

hadoop的distcp命令带用户名密码的方法
hadoop distcp -su user1,pass1 -du user1,pass1 hdfs://src1 hdfs://dest1

有时候两个集群之间是没有distcp权限的,这时候需要带上两个集群的账号密码,在-su后面带上第一个集群的账号密码,在-du后面带上目标集群的账号密码。

Mysql命令

 查看数据表的最详细的字段描述信息
SHOW FULL FIELDS FROM student

该命令把注释、权限、默认值、类型等表字段信息都列出来了。

查看正在执行的mysql线程

mysql> show processlist;

+———+———–+——————–+————-+———+——+——-+——————+

| Id      |    User   | Host               | db          | Command | Time | State | Info             |

+———+———–+——————–+————-+———+——+——-+——————+

| 2153201 | crazyant  | 127.0.0.1:25357    | pulse       | Sleep   |  914 |       | NULL             |

| 2153733 | crazyant  | 127.0.0.1:48814    | hive        | Query   |    0 | NULL  | show processlist |

| 2153735 | crazyant  | 127.0.0.1:39639    | pulse       | Sleep   |   13 |       | NULL             |

| 2153736 | crazyant  | 127.0.0.1:39640    | pulse       | Sleep   |   13 |       | NULL             |

+———+———–+——————–+————-+———+——+——-+——————+

4 rows in set (0.01 sec)

mysql>

使用kill命令可以把其中的一个进程给删了

mysql> kill 2153474;

Query OK, 0 rows affected (0.00 sec)

将数据LOAD到MYSQL的方法:

LOAD DATA LOCAL INFILE ‘D:/workbench/python/result.txt’ REPLACE INTO TABLE my_urlvisit FIELDS TERMINATED BY’\t’ LINES TERMINATED BY’\n’ IGNORE 0 LINES (url,pdate,COUNT);

vim命令

如果编辑错误,按ESC回到命令模式,按u可以撤销刚才的编辑;

vim编辑中文文本出现乱码

VIM的文本经常会出现中文乱码,这是因为fileencoding和termencoding编码不一致造成的,设置一直就可以了;

:set termencoding

termencoding=cp936

:set fileencoding

fileencoding=utf-8

:set termencoding=utf8

这样设置一下vim就能正常显示中文了;

转载请注明来源:http://crazyant.net/1209.html

为eclipse安装python、shell开发环境和SVN插件

eclipse是一个非常好用的IDE,通常来说我们都用eclipse来开发JAVA程序,为了让开发python、shell等脚本也能在eclipse上运行,出现了很多相关的插件:

  • python:pydev
  • shell:shelled
  • svn:Subclipse
  • PHP:PDT

使用eclipse过程中可以多搜一搜网上的插件,有些能大幅提高开发效率,本文以开发linux环境下的python、shell脚本为背景,安装了eclipse并在其上装上了开发python、shell、svn插件,其中shell插件可以指定shell解释器,这样就能在windows下的eclispe中直接运行shell程序。
继续阅读为eclipse安装python、shell开发环境和SVN插件

按大小拆分超大文件的方法(本文测试了一个62G的文件)

遇到一个问题,从网络上下载了一个62G的文件(新浪微博的语料集,地址:http://itee.uq.edu.au/~dke/WISE2012.htm),之后要进行其他处理,很显然先拆分成小文件再处理比较好。

我当时用的是windows系统,貌似没有这种拆分如此大的文件的工具,我本人试着用C++的内存映射方法(在内存里建一个内存映射文件,然后把超大文件的一部分映射到内存,然后分片读文件),将文件的一部分一部分读出来,读一部分换掉一部分然后写入小文件,从而达到拆分文件的目的,然而网上找了好多文章,内存映射这块还是没搞懂,尤其是参数很是复杂,只好放弃。

最后才发现,windows下面难以解决的问题,linux早就存在了现成的方案来解决,那就是split命令。split具体的使用方法贴一下:

linux split 命令

功能说明:切割文件。

语  法:split [–help][–version][-<行数>][-b <字节>][-C <字节>][-l <行数>][要切割的文件][输出文件名]

补充说明:split可将文件切成较小的文件,预设每1000行会切成一个小文件。

参  数:

-<行数>或-l<行数>  指定每多少行就要切成一个小文件。

-b<字节>  指定每多少字就要切成一个小文件。支持单位:m,k

-C<字节>  与-b参数类似,但切割时尽量维持每行的完整性。

–help  显示帮助。

–version  显示版本信息。

[输出文件名]  设置切割后文件的前置文件名,split会自动在前置文件名后再加上编号。

使用例子:

  split -b 100m filename

看过命令后,会发现其中的-C命令,会照顾到行,就是说截取的时候,不会将一行从中间截断,最终我只用了一行命令解决了问题:

split -C 1024m 62G.txt output

该命令将一个62G的文件,拆分成每个1G的小文件,并且不会将行拆开(新浪微博这个数据,每行一条,不能拆分)