强烈推荐!Python 资源大全
英文:vinta
译文:伯乐在线 – 艾凌风
链接:http://python.jobbole.com/84464/
Awesome Python ,这又是一个 Awesome XXX 系列的资源整理,由 vinta 发起和维护。内容包括:Web框架、网络爬虫、网络内容提取、模板引擎、数据库、数据可视化、图片处理、文本处理、自然语言处理、机器学习、日志、代码分析等。
伯乐在线已在 GitHub 上发起「Python 资源大全中文版」的整理。欢迎扩散、欢迎加入。
https://github.com/jobbole/awesome-python-cn
环境管理
管理 Python 版本和环境的工具
- p – 非常简单的交互式 python 版本管理工具。
- pyenv – 简单的 Python 版本管理工具。
- Vex – 可以在虚拟环境中执行命令。
- virtualenv – 创建独立 Python 环境的工具。
- virtualenvwrapper– virtualenv 的一组扩展。
包管理
管理包和依赖的工具。
- pip – Python 包和依赖关系管理工具。
- pip-tools – 保证 Python 包依赖关系更新的一组工具。
- conda – 跨平台,Python 二进制包管理工具。
- Curdling – 管理 Python 包的命令行工具。
- wheel – Python 分发的新标准,意在取代 eggs。
包仓库
本地 PyPI 仓库服务和代理。
- warehouse – 下一代 PyPI。
Warehouse bandersnatch – PyPA 提供的 PyPI 镜像工具。
- devpi – PyPI 服务和打包/测试/分发工具。
- localshop – 本地 PyPI 服务(自定义包并且自动对 PyPI 镜像)。
分发
打包为可执行文件以便分发。
- PyInstaller – 将 Python 程序转换成独立的执行文件(跨平台)。
- dh-virtualenv – 构建并将 virtualenv 虚拟环境作为一个 Debian 包来发布。
- Nuitka – 将脚本、模块、包编译成可执行文件或扩展模块。
- py2app – 将 Python 脚本变为独立软件包(Mac OS X)。
- py2exe – 将 Python 脚本变为独立软件包(Windows)。
- pynsist – 一个用来创建 Windows 安装程序的工具,可以在安装程序中打包 Python本身。
构建工具
将源码编译成软件。
- buildout – 一个构建系统,从多个组件来创建,组装和部署应用。
- BitBake – 针对嵌入式 Linux 的类似 make 的构建工具。
- fabricate – 对任何语言自动找到依赖关系的构建工具。
- PlatformIO – 多平台命令行构建工具。
- PyBuilder – 纯 Python 实现的持续化构建工具。
- SCons – 软件构建工具。
交互式解析器
交互式 Python 解析器。
- IPython – 功能丰富的工具,非常有效的使用交互式 Python。
- bpython– 界面丰富的 Python 解析器。
- ptpython – 高级交互式Python解析器, 构建于python-prompt-toolkit 之上。
文件
文件管理和 MIME(多用途的网际邮件扩充协议)类型检测。
- imghdr – (Python 标准库)检测图片类型。
- mimetypes – (Python 标准库)将文件名映射为 MIME 类型。
- path.py – 对 os.path 进行封装的模块。
- pathlib – (Python3.4+ 标准库)跨平台的、面向对象的路径操作库。
- python-magic– 文件类型检测的第三方库 libmagic 的 Python 接口。
- Unipath– 用面向对象的方式操作文件和目录
- watchdog – 管理文件系统事件的 API 和 shell 工具
日期和时间
操作日期和时间的类库。
- arrow– 更好的 Python 日期时间操作类库。
- Chronyk – Python 3 的类库,用于解析手写格式的时间和日期。
- dateutil – Python datetime 模块的扩展。
- delorean– 解决 Python 中有关日期处理的棘手问题的库。
- moment – 一个用来处理时间和日期的Python库。灵感来自于Moment.js。
- PyTime – 一个简单易用的Python模块,用于通过字符串来操作日期/时间。
- pytz – 现代以及历史版本的世界时区定义。将时区数据库引入Python。
- when.py – 提供用户友好的函数来帮助用户进行常用的日期和时间操作。
文本处理
用于解析和操作文本的库。
- 通用
chardet – 字符编码检测器,兼容 Python2 和 Python3。
difflib – (Python 标准库)帮助我们进行差异化比较。
ftfy – 让Unicode文本更完整更连贯。
fuzzywuzzy – 模糊字符串匹配。
Levenshtein – 快速计算编辑距离以及字符串的相似度。
pangu.py – 在中日韩语字符和数字字母之间添加空格。
pyfiglet -figlet 的 Python实现。
shortuuid – 一个生成器库,用以生成简洁的,明白的,URL 安全的 UUID。
unidecode – Unicode 文本的 ASCII 转换形式 。
uniout – 打印可读的字符,而不是转义的字符串。
xpinyin – 一个用于把汉字转换为拼音的库。
- Slug化
awesome-slugify – 一个 Python slug 化库,可以保持 Unicode。
python-slugify – Python slug 化库,可以把 unicode 转化为 ASCII。
unicode-slugify – 一个 slug 工具,可以生成 unicode slugs ,需要依赖 Django 。
- 解析器
phonenumbers – 解析,格式化,储存,验证电话号码。
PLY – lex 和 yacc 解析工具的 Python 实现。
Pygments – 通用语法高亮工具。
pyparsing – 生成通用解析器的框架。
python-nameparser – 把一个人名分解为几个独立的部分。
python-user-agents – 浏览器 user agent 解析器。
sqlparse – 一个无验证的 SQL 解析器。
特殊文本格式处理
一些用来解析和操作特殊文本格式的库。
- 通用
tablib – 一个用来处理中表格数据的模块。
- Office
Marmir – 把输入的Python 数据结构转换为电子表单。
openpyxl – 一个用来读写 Excel 2010 xlsx/xlsm/xltx/xltm 文件的库。
python-docx – 读取,查询以及修改 Microsoft Word 2007/2008 docx 文件。
unoconv – 在 LibreOffice/OpenOffice 支持的任意文件格式之间进行转换。
XlsxWriter – 一个用于创建 Excel .xlsx 文件的 Python 模块。
xlwings – 一个使得在 Excel 中方便调用 Python 的库(反之亦然),基于 BSD 协议。
xlwt / xlrd – 读写 Excel 文件的数据和格式信息。
relatorio – 模板化OpenDocument 文件。
PDFMiner – 一个用于从PDF文档中抽取信息的工具。
PyPDF2 – 一个可以分割,合并和转换 PDF 页面的库。
ReportLab – 快速创建富文本 PDF 文档。
- Markdown
Mistune – 快速并且功能齐全的纯 Python 实现的 Markdown 解析器。
Python-Markdown – John Gruber’s Markdown 的 Python 版实现。
- YAML
PyYAML – Python 版本的 YAML 解析器。
- CSV
csvkit – 用于转换和操作 CSV 的工具。
- Archive
unp – 一个用来方便解包归档文件的命令行工具。
自然语言处理
用来处理人类语言的库。
- NLTK – 一个先进的平台,用以构建处理人类语言数据的 Python 程序。
- jieba – 中文分词工具。
- langid.py – 独立的语言识别系统。
- Pattern – Python 网络信息挖掘模块。
- SnowNLP – 一个用来处理中文文本的库。
- TextBlob – 为进行普通自然语言处理任务提供一致的 API。
- TextGrocery – 一简单高效的短文本分类工具,基于 LibLinear 和 Jieba。
文档
用以生成项目文档的库。
- Sphinx – Python 文档生成器。
awesome-sphinxdoc
- MkDocs – 对 Markdown 友好的文档生成器。
- pdoc – 一个可以替换Epydoc 的库,可以自动生成 Python 库的 API 文档。
- Pycco – 文学编程(literate-programming)风格的文档生成器。
配置
用来保存和解析配置的库。
- config – logging 模块作者写的分级配置模块。
- ConfigObj – INI 文件解析器,带验证功能。
- ConfigParser – (Python 标准库) INI 文件解析器。
- profig – 通过多种格式进行配置,具有数值转换功能。
- python-decouple – 将设置和代码完全隔离。
命令行工具
用于创建命令行程序的库。
- 命令行程序开发
cement – Python 的命令行程序框架。
click – 一个通过组合的方式来创建精美命令行界面的包。
cliff – 一个用于创建命令行程序的框架,可以创建具有多层命令的命令行程序。
clint – Python 命令行程序工具。
colorama – 跨平台彩色终端文本。
docopt – Python 风格的命令行参数解析器。
Gooey – 一条命令,将命令行程序变成一个 GUI 程序。
python-prompt-toolkit – 一个用于构建强大的交互式命令行程序的库。
- 生产力工具
aws-cli – Amazon Web Services 的通用命令行界面。
bashplotlib – 在终端中进行基本绘图。
caniusepython3 – 判断是哪个项目妨碍你你移植到 Python 3。
cookiecutter – 从 cookiecutters(项目模板)创建项目的一个命令行工具。
doitlive – 一个用来在终端中进行现场演示的工具。
howdoi – 通过命令行获取即时的编程问题解答。
httpie – 一个命令行HTTP 客户端,cURL 的替代品,易用性更好。
PathPicker – 从bash输出中选出文件。
percol – 向UNIX shell 传统管道概念中加入交互式选择功能。
SAWS – 一个加强版的 AWS 命令行。
thefuck – 修正你之前的命令行指令。
mycli – 一个 MySQL 命令行客户端,具有自动补全和语法高亮功能。
pgcli – Postgres 命令行工具,具有自动补全和语法高亮功能。
下载器
用来进行下载的库.
- s3cmd – 一个用来管理Amazon S3 和 CloudFront 的命令行工具。
- s4cmd – 超级 S3 命令行工具,性能更加强劲。
- you-get – 一个 YouTube/Youku/Niconico 视频下载器,使用 Python3 编写。
- youtube-dl – 一个小巧的命令行程序,用来下载 YouTube 视频。
图像处理
用来操作图像的库.
- pillow – Pillow 是一个更加易用版的 PIL。
- hmap – 图像直方图映射。
- imgSeek – 一个使用视觉相似性搜索一组图片集合的项目。
- nude.py – 裸体检测。
- pyBarcode – 不借助 PIL 库在 Python 程序中生成条形码。
- pygram – 类似 Instagram 的图像滤镜。
- python-qrcode – 一个纯 Python 实现的二维码生成器。
- Quads – 基于四叉树的计算机艺术。
- scikit-image – 一个用于(科学)图像处理的 Python 库。
- thumbor – 一个小型图像服务,具有剪裁,尺寸重设和翻转功能。
- wand – MagickWand的Python 绑定。MagickWand 是 ImageMagick的 C API 。
OCR
光学字符识别库。
- pyocr – Tesseract 和 Cuneiform 的一个封装(wrapper)。
- pytesseract – Google Tesseract OCR 的另一个封装(wrapper)。
- python-tesseract – Google Tesseract OCR 的一个包装类。
音频
用来操作音频的库
- audiolazy -Python 的数字信号处理包。
- audioread – 交叉库 (GStreamer + Core Audio + MAD + FFmpeg) 音频解码。
- beets – 一个音乐库管理工具及 MusicBrainz 标签添加工具
- dejavu – 音频指纹提取和识别
- django-elastic-transcoder – Django + Amazon Elastic Transcoder。
- eyeD3 – 一个用来操作音频文件的工具,具体来讲就是包含 ID3 元信息的 MP3 文件。
- id3reader – 一个用来读取 MP3 元数据的 Python 模块。
- m3u8 – 一个用来解析 m3u8 文件的模块。
- mutagen – 一个用来处理音频元数据的 Python 模块。
- pydub – 通过简单、简洁的高层接口来操作音频文件。
- pyechonest – Echo Nest API 的 Python 客户端
- talkbox – 一个用来处理演讲/信号的 Python 库
- TimeSide – 开源 web 音频处理框架。
- tinytag – 一个用来读取MP3, OGG, FLAC 以及 Wave 文件音乐元数据的库。
- mingus – 一个高级音乐理论和曲谱包,支持 MIDI 文件和回放功能。
Video
用来操作视频和GIF的库。
- moviepy – 一个用来进行基于脚本的视频编辑模块,适用于多种格式,包括动图 GIFs。
- scikit-video – SciPy 视频处理常用程序。
地理位置
地理编码地址以及用来处理经纬度的库。
- GeoDjango – 世界级地理图形 web 框架。
- GeoIP – MaxMind GeoIP Legacy 数据库的 Python API。
- geojson – GeoJSON 的 Python 绑定及工具。
- geopy – Python 地址编码工具箱。
- pygeoip – 纯 Python GeoIP API。
- django-countries – 一个 Django 应用程序,提供用于表格的国家选择功能,国旗图标静态文件以及模型中的国家字段。
HTTP
使用HTTP的库。
- requests – 人性化的HTTP请求库。
- grequests – requests 库 + gevent ,用于异步 HTTP 请求.
- httplib2 – 全面的 HTTP 客户端库。
- treq – 类似 requests 的Python API 构建于 Twisted HTTP 客户端之上。
- urllib3 – 一个具有线程安全连接池,支持文件 post,清晰友好的 HTTP 库。
数据库
Python实现的数据库。
- pickleDB – 一个简单,轻量级键值储存数据库。
- PipelineDB – 流式 SQL 数据库。
- TinyDB – 一个微型的,面向文档型数据库。
- ZODB – 一个 Python 原生对象数据库。一个键值和对象图数据库。
数据库驱动
用来连接和操作数据库的库。
- MySQL – awesome-mysql系列
mysql-python – Python 的 MySQL 数据库连接器。
mysqlclient – mysql-python 分支,支持 Python 3。
oursql – 一个更好的 MySQL 连接器,支持原生预编译指令和 BLOBs.
PyMySQL – 纯 Python MySQL 驱动,兼容 mysql-python。
- PostgreSQL
psycopg2 – Python 中最流行的 PostgreSQL 适配器。
queries – psycopg2 库的封装,用来和 PostgreSQL 进行交互。
txpostgres – 基于 Twisted 的异步 PostgreSQL 驱动。
- 其他关系型数据库
apsw – 另一个 Python SQLite封装。
dataset – 在数据库中存储Python字典 – 可以协同SQLite,MySQL,和 PostgreSQL工作。
pymssql– 一个简单的Microsoft SQL Server数据库接口。
- NoSQL 数据库
cassandra-python-driver – Cassandra 的 Python 驱动。
HappyBase – 一个为 Apache HBase 设计的,对开发者友好的库。
Plyvel – 一个快速且功能丰富的 LevelDB 的 Python 接口。
py2neo – Neo4j restful 接口的Python 封装客户端。
pycassa – Cassandra 的 Python Thrift 驱动。
PyMongo – MongoDB 的官方 Python 客户端。
redis-py – Redis 的 Python 客户端。
telephus – 基于 Twisted 的 Cassandra 客户端。
txRedis – 基于 Twisted 的 Redis 客户端。
ORM
实现对象关系映射或数据映射技术的库。
- 关系型数据库
Django Models – Django 的一部分。
SQLAlchemy – Python SQL 工具以及对象关系映射工具。
awesome-sqlalchemy系列
Peewee – 一个小巧,富有表达力的 ORM。
PonyORM – 提供面向生成器的 SQL 接口的 ORM。
python-sql – 编写 Python 风格的 SQL 查询。
- NoSQL 数据库
django-mongodb-engine – Django MongoDB 后端。
PynamoDB – Amazon DynamoDB 的一个 Python 风格接口。
flywheel – Amazon DynamoDB 的对象映射工具。
MongoEngine – 一个Python 对象文档映射工具,用于 MongoDB。
hot-redis – 为 Redis 提供 Python 丰富的数据类型。
redisco – 一个 Python 库,提供可以持续存在在 Redis 中的简单模型和容器。
- 其他
butterdb – Google Drive 电子表格的 Python ORM。
Web 框架
全栈 web 框架。
- Django – Python 界最流行的 web 框架。
awesome-django系列
- Flask – 一个 Python 微型框架。
awesome-flask系列
- Pyramid – 一个小巧,快速,接地气的开源Python web 框架。
awesome-pyramid系列
- Bottle – 一个快速小巧,轻量级的 WSGI 微型 web 框架。
- CherryPy – 一个极简的 Python web 框架,服从 HTTP/1.1 协议且具有WSGI 线程池。
- TurboGears – 一个可以扩展为全栈解决方案的微型框架。
- web.py – 一个 Python 的 web 框架,既简单,又强大。
- web2py – 一个全栈 web 框架和平台,专注于简单易用。
- Tornado – 一个web 框架和异步网络库。
权限
允许或拒绝用户访问数据或功能的库。
- Carteblanche – Module to align code with thoughts of users and designers. Also magically handles navigation and permissions.
- django-guardian – Django 1.2+ 实现了单个对象权限。
- django-rules – 一个小巧但是强大的应用,提供对象级别的权限管理,且不需要使用数据库。
CMS
内容管理系统
- django-cms – 一个开源的,企业级 CMS,基于 Django。
- djedi-cms – 一个轻量级但却非常强大的 Django CMS ,考虑到了插件,内联编辑以及性能。
- FeinCMS – 基于 Django 构建的最先进的内容管理系统之一。
- Kotti – 一个高级的,Python 范的 web 应用框架,基于 Pyramid 构建。
- Mezzanine – 一个强大的,持续的,灵活的内容管理平台。
- Opps – 一个为杂志,报纸网站以及大流量门户网站设计的 CMS 平台,基于 Django。
- Plone – 一个构建于开源应用服务器 Zope 之上的 CMS。
- Quokka – 灵活,可扩展的小型 CMS,基于 Flask 和 MongoDB。
- Wagtail – 一个 Django 内容管理系统。
- Widgy – 最新的 CMS 框架,基于 Django。
电子商务
用于电子商务以及支付的框架和库。
- django-oscar – 一个用于 Django 的开源的电子商务框架。
- django-shop – 一个基于 Django 的店铺系统。
- Cartridge – 一个基于 Mezzanine 构建的购物车应用。
- shoop – 一个基于 Django 的开源电子商务平台。
- alipay – 非官方的 Python 支付宝 API。
- merchant – 一个可以接收来自多种支付平台支付的 Django 应用。
- money – 货币类库with optional CLDR-backed locale-aware formatting and an extensible currency exchange solution.
- python-currencies – 显示货币格式以及它的数值。
RESTful API
用来开发RESTful APIs的库
- Django
django-rest-framework – 一个强大灵活的工具,用来构建 web API。
django-tastypie – 为Django 应用开发API。
django-formapi – 为 Django 的表单验证,创建 JSON APIs 。
- Flask
flask-api – 为 flask 开发的,可浏览 Web APIs 。
flask-restful – 为 flask 快速创建REST APIs 。
flask-restless – 为 SQLAlchemy 定义的数据库模型创建 RESTful APIs 。
flask-api-utils – 为 Flask 处理 API 表示和验证。
eve – REST API 框架,由 Flask, MongoDB 等驱动。
- Pyramid
cornice – 一个Pyramid 的 REST 框架 。
- 与框架无关的
falcon – 一个用来建立云 API 和 web app 后端的噶性能框架。
sandman – 为现存的数据库驱动系统自动创建 REST APIs 。
restless – 框架无关的 REST 框架 ,基于从 Tastypie 学到的知识。
ripozo – 快速创建 REST/HATEOAS/Hypermedia APIs。
验证
实现验证方案的库。
- OAuth
Authomatic – 简单但是强大的框架,身份验证/授权客户端。
django-allauth – Django 的验证应用。
django-oauth-toolkit – 为 Django 用户准备的 OAuth2。
django-oauth2-provider – 为 Django 应用提供 OAuth2 接入。
Flask-OAuthlib – OAuth 1.0/a, 2.0 客户端实现,供 Flask 使用。
OAuthLib – 一个 OAuth 请求-签名逻辑通用、 完整的实现。
python-oauth2 – 一个完全测试的抽象接口。用来创建 OAuth 客户端和服务端。
python-social-auth – 一个设置简单的社会化验证方式。
rauth – OAuth 1.0/a, 2.0, 和 Ofly 的 Python 库。
sanction – 一个超级简单的OAuth2 客户端实现。
- 其他
jose – JavaScript 对象签名和加密草案的实现。
PyJWT – JSON Web 令牌草案 01。
python-jws – JSON Web 签名草案 02 的实现。
python-jwt – 一个用来生成和验证 JSON Web 令牌的模块。
模板引擎
模板生成和词法解析的库和工具。
- Jinja2 – 一个现代的,对设计师友好的模板引擎。
- Chameleon – 一个 HTML/XML 模板引擎。 模仿了 ZPT(Zope Page Templates), 进行了速度上的优化。
- Genshi – Python 模板工具,用以生成 web 感知的结果。
- Mako – Python 平台的超高速轻量级模板。
Queue
处理事件以及任务队列的库。
- celery – 一个异步任务队列/作业队列,基于分布式消息传递。
- huey – 小型多线程任务队列。
- mrq – Mr. Queue -一个 Python 的分布式 worker 任务队列, 使用 Redis 和 gevent。
- rq – 简单的 Python 作业队列。
- simpleq – 一个简单的,可无限扩张的,基于亚马逊 SQS 的队列。
搜索
对数据进行索引和执行搜索查询的库和软件。
- django-haystack – Django 模块化搜索。
- elasticsearch-py – Elasticsearch 的官方底层 Python 客户端。
- elasticsearch-dsl-py -Elasticsearch 的官方高级 Python 客户端。
- solrpy – solr的 Python 客户端。
- Whoosh – 一个快速的纯 Python 搜索引擎库。
动态消息
用来创建用户活动的库。
- django-activity-stream – 从你的站点行为中生成通用活动信息流。
- Stream-Framework – 使用 Cassandra 和 Redis 创建动态消息和通知系统。
资源管理
管理、压缩、缩小网站资源的工具。
- django-compressor – 将链接和内联的 JavaScript 或 CSS 压缩到一个单独的缓存文件中。
- django-storages – 一个针对 Django 的自定义存储后端的工具集合。
- fanstatic – 打包、优化,并且把静态文件依赖作为 Python 的包来提供。
- File Conveyor – 一个后台驻留的程序,用来发现和同步文件到 CDNs, S3 和 FTP。
- Flask-Assets – 帮你将 web 资源整合到你的 Flask app 中。
- jinja-assets-compressor – 一个 Jinja 扩展,用来编译和压缩你的资源。
- webassets – 为你的静态资源打包、优化和管理生成独一无二的缓存 URL。
电子邮件
用来发送和解析电子邮件的库。
- django-celery-ses – 带有 AWS SES 和 Celery 的 Django email 后端。
- envelopes – 供人类使用的电子邮件库。
- flanker – 一个 email 地址和 Mime 解析库。
- imbox – Python IMAP 库
- inbox.py – Python SMTP 服务器。
- inbox – 一个开源电子邮件工具箱。
- lamson – Python 风格的 SMTP 应用服务器。
- mailjet – Mailjet API 实现,用来提供批量发送邮件,统计等功能。
- marrow.mailer – 高性能可扩展邮件分发框架。
- modoboa – 一个邮件托管和管理平台,具有现代的、简约的 Web UI。
- pyzmail – 创建,发送和解析电子邮件。
- Talon – Mailgun 库,用来抽取信息和签名。
URL处理
解析URLs的库
- furl – 一个让处理 URL 更简单小型 Python 库。
- purl – 一个简单的,不可变的URL类,具有简洁的 API 来进行询问和处理。
- pyshorteners – 一个纯 Python URL 缩短库。
- shorturl– 生成短小 URL 和类似 bit.ly 短链的Python 实现。
- webargs – 一个解析 HTTP 请求参数的库,内置对流行 web 框架的支持,包括 Flask, Django, Bottle, Tornado和 Pyramid。
HTML处理
处理 HTML和XML的库。
- BeautifulSoup – 以 Python 风格的方式来对 HTML 或 XML 进行迭代,搜索和修改。
- bleach – 一个基于白名单的 HTML 清理和文本链接库。
- cssutils – 一个 Python 的 CSS 库。
- html5lib – 一个兼容标准的 HTML 文档和片段解析及序列化库。
- lxml – 一个非常快速,简单易用,功能齐全的库,用来处理 HTML 和 XML。
- MarkupSafe – 为Python 实现 XML/HTML/XHTML 标记安全字符串。
- pyquery – 一个解析 HTML 的库,类似 jQuery。
- untangle – 将XML文档转换为Python对象,使其可以方便的访问。
- xhtml2pdf – HTML/CSS 转 PDF 工具。
- xmltodict – 像处理 JSON 一样处理 XML。
网络站点爬取
爬取网络站点的库
- Scrapy – 一个快速高级的屏幕爬取及网页采集框架。
- cola – 一个分布式爬虫框架。
- Demiurge – 基于PyQuery 的爬虫微型框架。
- feedparser – 通用 feed 解析器。
- Grab – 站点爬取框架。
- MechanicalSoup – 用于自动和网络站点交互的 Python 库。
- portia – Scrapy 可视化爬取。
- pyspider – 一个强大的爬虫系统。
- RoboBrowser – 一个简单的,Python 风格的库,用来浏览网站,而不需要一个独立安装的浏览器。
网页内容提取
用于进行网页内容提取的库。
- Haul – 一个可以扩展的图像爬取工具。
- html2text – 将 HTML 转换为 Markdown 格式文本
- lassie – 人性化的网页内容检索库。
- micawber -一个小型网页内容提取库,用来从 URLs 提取富内容。
- newspaper – 使用 Python 进行新闻提取,文章提取以及内容策展。
- opengraph – 一个用来解析开放内容协议(Open Graph Protocol)的 Python模块。
- python-goose – HTML内容/文章提取器。
- python-readability– arc90 公司 readability 工具的 Python 高速端口
- sanitize – 为杂乱的数据世界带来调理性。
- sumy – 一个为文本文件和 HTML 页面进行自动摘要的模块。
- textract – 从任何格式的文档中提取文本,Word,PowerPoint,PDFs 等等。
表单
进行表单操作的库。
- Deform – Python HTML 表单生成库,受到了 formish 表单生成库的启发。
- django-bootstrap3– 集成了 Bootstrap 3 的 Django。
- django-crispy-forms – 一个 Django 应用,他可以让你以一种非常优雅且 DRY(Don’t repeat yourself) 的方式来创建美观的表单。
- django-remote-forms– 一个平台独立的 Django 表单序列化工具。
- WTForms – 一个灵活的表单验证和呈现库。
- WTForms-JSON– 一个 WTForms 扩展,用来处理 JSON 数据。
数据验证
数据验证库。多用于表单验证。
- Cerberus – A mappings-validator with a variety of rules, normalization-features and simple customization that uses a pythonic schema-definition.
- colander – 一个用于对从 XML, JSON,HTML 表单获取的数据或其他同样简单的序列化数据进行验证和反序列化的系统。
- kmatch – 一种用于匹配/验证/筛选 Python 字典的语言。
- schema -一个用于对 Python 数据结构进行验证的库。
- Schematics – 数据结构验证。
- valideer – 轻量级可扩展的数据验证和适配库。
- voluptuous – 一个 Python 数据验证库。主要是为了验证传入 Python的 JSON,YAML 等数据。
静态站点生成器
静态站点生成器是一个软件,它把文本和模板作为输入,然后输出HTML文件。
- Pelican – 使用 Markdown 或 ReST 来处理内容, Jinja 2 来制作主题。支持 DVCS, Disqus.。AGPL 许可。
- Cactus – 为设计师设计的静态站点生成器。
- Hyde – 基于 Jinja2 的静态站点生成器。
- Nikola – 一个静态网站和博客生成器。
- Tinkerer – Tinkerer 是一个博客引擎/静态站点生成器,由Sphinx驱动。
- Lektor – 一个简单易用的静态 CMS 和博客引擎。
更多资源
- 由于资源过多,导致字数超过微信限制了;
- 微信图文不支持超链接,前面提到的各资源,无法查看详情;
- 大家点击「阅读原文」,可查看 python 大全完整版,并且查看本文提到的各资源。http://python.jobbole.com/84464/
伯乐在线已在 GitHub 上发起「Python 资源大全中文版」的整理。欢迎扩散、欢迎加入。 https://github.com/jobbole/awesome-python-cn
译者简介 ( 点击 → 加入专栏作者 )
艾凌风:尚未入职小码农;翻译组的勤务员;C/Python/在线教育/英文翻译
浅谈Web缓存
来自:腾讯AlloyTeam Blog
by TAT.yana
链接:http://www.alloyteam.com/2016/03/discussion-on-web-caching/(点击尾部阅读原文前往)
在前端开发中,性能一直都是被大家所重视的一点,然而判断一个网站的性能最直观的就是看网页打开的速度。其中提高网页反应速度的一个方式就是使用缓存。一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。那么下面我们就来看看服务器端缓存的原理。
缓存分类
web缓存分为很多种,比如数据库缓存、代理服务器缓存、还有我们熟悉的CDN缓存,以及浏览器缓存。对于太多文字的阅读其实我是拒绝的,于是就画了个图来解释下。
浏览器通过代理服务器向源服务器发起请求的原理如下图,
浏览器先向代理服务器发起Web请求,再将请求转发到源服务器。它属于共享缓存,所以很多地方都可以使用其缓存资源,因此对于节省流量有很大作用。
浏览器缓存是将文件保存在客户端,在同一个会话过程中会检查缓存的副本是否足够新,在后退网页时,访问过的资源可以从浏览器缓存中拿出使用。通过减少服务器处理请求的数量,用户将获得更快的体验
下面我就来着重讲下传说中的浏览器缓存。
浏览器缓存
页面的缓存状态是由header决定的,header的参数有四种:
一、Cache-Control:
1、max-age(单位为s)指定设置缓存最大的有效时间,定义的是时间长短。当浏览器向服务器发送请求后,在max-age这段时间里浏览器就不会再向服务器发送请求了。
我们来找个资源看下。比如shang.qq.com上的css资源,max-age=2592000,也就是说缓存有效期为2592000秒(也就是30天)。于是在30天内都会使用这个版本的资源,即使服务器上的资源发生了变化,浏览器也不会得到通知。max-age会覆盖掉Expires,后面会有讨论。
2、s-maxage(单位为s)同max-age,只用于共享缓存(比如CDN缓存)。
比如,当s-maxage=60时,在这60秒中,即使更新了CDN的内容,浏览器也不会进行请求。也就是说max-age用于普通缓存,而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖掉max-age和Expires header。
3、public 指定响应会被缓存,并且在多用户间共享。也就是下图的意思。如果没有指定public还是private,则默认为public。
4、private 响应只作为私有的缓存(见下图),不能在用户间共享。如果要求HTTP认证,响应会自动设置为private。
5、no-cache 指定不缓存响应,表明资源不进行缓存,比如,
但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间。
6、no-store 绝对禁止缓存,一看就知道如果用了这个命令当然就是不会进行缓存啦~每次请求资源都要从服务器重新获取。
7、must-revalidate指定如果页面是过期的,则去服务器进行获取。这个指令并不常用,就不做过多的讨论了。
二、Expires
缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。但在上面我们提到过,cache-control的优先级更高。 Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
三、Last-modified
服务器端文件的最后修改时间,需要和cache-control共同使用,是检查服务器端资源是否更新的一种方式。当浏览器再次进行请求时,会向服务器传送If-Modified-Since报头,询问Last-Modified时间点之后资源是否被修改过。如果没有修改,则返回码为304,使用缓存;如果修改过,则再次去服务器请求资源,返回码和首次请求相同为200,资源为服务器最新资源。
如下图,最后修改时间为2014年12月19日星期五2点50分47秒
四、ETag
根据实体内容生成一段hash字符串,标识资源的状态,由服务端产生。浏览器会将这串字符串传回服务器,验证资源是否已经修改,如果没有修改,过程如下:
使用ETag可以解决Last-modified存在的一些问题:
a、某些服务器不能精确得到资源的最后修改时间,这样就无法通过最后修改时间判断资源是否更新
b、如果资源修改非常频繁,在秒以下的时间内进行修改,而Last-modified只能精确到秒
c、一些资源的最后修改时间改变了,但是内容没改变,使用ETag就认为资源还是没有修改的。
使用缓存流程
还是用图说话,下面是我所总结的从浏览器请求到展示资源的过程:
cache-control指令使用
说了那么多cache-control的指令,那么如何选择使用哪些指令呢?我还是不说话==
额外的
除了开头提到的那么多缓存方式以外,还有一种我们都熟悉的缓存方式,LocalStorage和sessionStorage(好像是两种23333)。
LocalStorage是一种本地存储的公共资源,域名下很多应用共享这份资源会有风险;LocalStorage是以页面域名划分的,如果有多个等价域名之间的LocalStorage不互通,则会造成缓存多份浪费。
LocalStorage在PC上的兼容性不太好,而且当网络速度快、协商缓存响应快时使用localStorage的速度比不上304。并且不能缓存css文件。而移动端由于网速慢,使用localStorage要快于304。
在html中加载一个png图,首次加载的时候时间如下图,
然而将图片使用了LocalStorage存储后,再次刷新后加载时间为0。
而相对LocalStorage来说,SessionStorage的数据只存储到特定的会话中,不属于持久化的存储,所以关闭浏览器会清除数据。和localstorage具有相同的方法。
在前端开发中缓存是必不可少的,那么使用怎样的缓存方式更高效、让我们项目的性能更优,还是需要我们仔细斟酌。
Java性能优化全攻略
来自:慧都控件网
链接:https://www.evget.com/article/2016/5/17/24105.html
原文:http://www.oracle.com/technetwork/java/javaseproducts/mission-control/java-mission-control-wp-2008279.pdf
让Java应用程序运行是一回事,但让他们跑得快就是另外一回事了。在面对对象的环境中,性能问题就像来势凶猛的野兽。但JVM的复杂性将性能调整的复杂程度增加了一个级别。这里Refcard涵盖了JVM internals、class loading(Java8中更新以映射最新的元空间)、垃圾回收、故障诊断、检测、并发性,等等。
介绍
Java是目前软件开发领域中使用最广泛的编程语言之一。Java应用程序在许多垂直领域(银行、电信、医疗保健等)中都有广泛使用。Refcard的目的是,帮助开发者通过专注于JVM内部,性能调整原则和最佳实践,以及利用现有监测和故障诊断工具,来提升应用程序在商业环境中的性能。
它能以不同的方式定义“optimal performance(最佳性能)”,但基本要素是:Java程序在业务响应时间要求内执行计算任务的能力,程序在高容量下执行业务功能的能力,并具有可靠性高和延迟低的特点。有时,数字本身变得模式化:对于一些大型网站,优秀的页面响应时间应该在500ms以下。在适当的时候,Refcard包括目标数字。但在大多数情况下,您需要根据业务需求和现有的性能基准自己决定这些。
JVM Internals
基础知识
代码编译和JIT
编译Java字节码显然没有直接从主机执行本机代码那么快。为了提高性能,Hotspot JVM找出最繁忙的字节码区域,然后将其编译成更高效地原生、机器代码(自适应优化)。然后这种本地代码就会存储在非堆内存中的代码缓存中。
注意:多数的JVM是通过禁用JIT编译器实现的(Djava.compiler=NONE)。您只需要考虑禁用的关键性优化,比如JVM崩溃。
下图说明了Java源代码,即时编译流程和生命周期。
内存空间
HotSpot Java Virtual Machine是由以下的存储空间组成。
类加载
Java的另一个重要特点是,在JVM启动之后,它能够加载编译的Java类(字节码)。根据程序的大小,在刚刚重启之后,程序在类加载过程中性能会显著降低。这种现象是因为内部JIT编译器在重启之后需要重新开始优化。
自JDK 1.7版本之后,有一些改进值得大家重视。例如默认的JDK class loader具有更好的装在类并发能力。
热点
故障诊断和监视
垃圾回收
Java垃圾回收流程对于程序性能是至关重要的。为了提供有效的垃圾回收,Heap(堆)本质上是划分在子区域中。
堆区域
GC Collectors
选择正确的collector或GC policy可以将程序的性能、可扩展性和可靠性优化到最佳状态。许多应用程序对于响应时间延迟都很敏感,因此大多需要使用并发的回收器,例如HotSpot CMS或IBM GC policy balanced。
我们强烈建议您通过适当的性能和负载测试确定最合适的GC策略。应该在生产环境中执行全面监控策略,以跟踪整体的JVM性能,并确定在之后需要改进的领域。
Garbage First (G1) Collector
HotSpot G1 collector是专为是专为满足用户定义的垃圾回收(GC)高概率暂停时间设计的,同时实现高吞吐量。
最新的HotSpot collector将heap基本划分到一组大小相等的堆区域,虚拟内存的每个区域连续范围。它将回收压缩的活动集中在heap区域,那里充满了可回收的对象(garbage first)。换句话说就是,这个区域有最低限度的“live”对象。
Oracle建议在以下例子和情况下使用G1 collector,尤其是对于目前正在使用CMS或parallel collectors的:
- 专为large heaps(>= 6 GB),并限制GC延迟(暂停时间<= 0.5秒)的应用程序设计。
- 超过50%的Java heap被实时数据占用(对象不能被GC回收)。
- 对象分析率和促进作用显著变化。
- 不期望过长的垃圾回收或压缩停顿(超过0.5至1秒)。
Java Heap尺寸
你一定要知道没有GC策略可以挽救Java Heap尺寸不足的现象。这些演习涉及到为不同的存储空间(包括新旧不同的版本)配置最大和最小的容量,包括元数据和本地内存容量。这里有一些建议准则:
- 在32-bit或64-bit JVM之间进行明智的选择。如果程序运行需要超过2GB内存,并且JVM暂停时间在可接受范围内,可以考虑使用64-bit JVM。
- 永远将应用程序放在第一考虑。确保将其配置好,并根据程序的内存占用量调整heap尺寸。建议通过性能和负载测试来衡量实时数据占有量。
- larger heap并不总是表现得更好、更快,因此不需要过度调整Java heap。并行中的JVM性能调优,找准机会减少或“spread”程序的内存占有量,以保证JVM的平均响应时间<1%。
- 对于32-bit JVM,为了从元数据和本地heap中留出一些内存,考虑2GB的最大heap尺寸。
- 对于64-bit JVM,我们要想办法在垂直和水平层面进行扩展,而不是试图将Java heap尺寸增加到15GB以上。这种做法往往提供更好的吞吐量,更好地利用硬件,提高应用程序的故障切换功能。
- 不许重复开发:充分利用开源以及商业故障排除的优势和监控工具,使这些变成可能。APM(应用性能管理)产品在过去十年里发展迅猛。
JDK 1.8 Metaspace指南
Hot Spots
故障诊断和监视
Java并发性
Java并发性可以定义为程序同时执行多个任务的能力。对于大型的Java EE系统,这意味着执行多个用户的业务功能的同时,实现最佳的吞吐量和性能的能力。
无论是硬件能力还是JVM稳定状况,Java并发性问题可能引起程序的瘫痪,严重影响程序的整体性能和可用性。
Thread Lock Contention
当您评估Java应用程序的并发线程的稳定状况时,你会经常遇到Thread lock contention的问题,这是目前最常见的Java并发问题。
例如:Thread lock contention会触发non-stop,它会尝试将一个缺少Java类(ClassNotFoundException的)加载到默认的JDK 1.7 ClassLoader。
如果您在成熟的技术环境中遇见像Thread Dump analysis这样的问题,我们强烈建议您积极面对它。这个问题的根源通常不同于之前的Java synchronization to legitimate IO blocking或者其他的non-thread safe calls。Lock contention问题往往是另一个问题的“症状”。
Java-level Deadlocks
真正的Java-level deadlocks是不太常见的,它同样可以极大程度地影响应用程序的性能和稳定性。当遇到两个或多个线程永远阻塞的时候,就会触发这样的问题。这种情况不同于其他常见的那种“day-to-day”线程问题,例如 lock contention、threads waiting on blocking IO calls等等。真正的lock-ordering deadlock问题可以被看做如下:
Oracle HotSpot 和IBM JVM为大多数的deadlock detectors情况提供了解决方案,帮助您快速找出造成这种状况的罪魁祸首的线程。遇到类似lock contention troubleshooting的问题,建议从诸如线程转储分析为出发点来解决该问题。
一旦找到造成问题的代码根源,解决方案涉及lock-ordering条件寻址和来自JDK其他可用的并发编程技术,如java.util.concurrent.locks.ReentrantLock,提供了诸如tryLock()的方法。这种方法给予开发人员更大的灵活性,也为防止deadlock和thread lock “starvation”提供了更多方式。
Clock Time和CPU Burn
在进行JVM调优的同时,也有必要检查应用程序的行为,更确切地说是最高clock time和CPU burn的贡献者。
当Java垃圾回收和线程并发不再是压力点,深入到你的应用程序代码的执行模式,并专注于顶级响应时间贡献者(也叫作clock time)是很重要的。检查应用程序代码的消CPU耗和Java 线程(CPU burn)也同样至关重要。CPU使用率较高(>75%)是不正常的(良好的物理资源的利用率)。因为这往往意味着效率低下和容量问题。对于大型的Java EE企业应用,保持安全的CPU缓冲区是必要的,以应对突发的负载冲击情况。
摒弃那些传统的跟踪方法,如在代码中加入响应时间“日志”。Java剖析工具和APM解决方案恰恰可以帮助您分析这类型的问题。这种方式更加高效、可靠。对于Java生产环境缺乏一个强大的APM解决方案。您仍然可以依赖诸如Java VisualVM的工具,通过多个快照进行thread dump分析,并使用OS CPU分析每个线程。
最后的建议是,不要妄图同时解决所有的问题。列出排在最前面的5个clock time和CPU burn问题,然后寻找解决方案。
Application预算
其他关于Java应用程序性能的重要方面是稳定性和可靠性。在有着99.9%典型可用目标的SLA umbrella下,稳定和可靠对于程序的操作尤为重要。这些系统应该具有高容错级别,并对应用和资源进行严格的预算,以防止发生多米诺效应。用这种方法可以防止一些这样的情况,例如,一个业务流程使用所有可用的物理,中间件或JVM资源。
Hot Spots
超时管理
Java application与外部系统之间缺乏合理的超时时间,由于中间件和JVM线程消耗(blocking IO calls),可能导致严重的性能下降和中断。合理的超时时间可以避免在遇到外部服务提供商速度缓慢的时候,Java线程等待太久。
工具
详解Java定时任务
来自:博客园
作者: chenssy
链接: http://www.cnblogs.com/chenssy/p/3788407.html
在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现。下面LZ就其原理、实例以及Timer缺陷三个方面来解析Java Timer定时器。
一、简介
在Java中一个完整定时任务需要由Timer、TimerTask两个类来配合完成。 API中是这样定义他们的,Timer:一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。由TimerTask:Timer 安排为一次执行或重复执行的任务。我们可以这样理解Timer是一种定时器工具,用来在一个后台线程计划执行指定任务,而TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。
Timer类
在工具类Timer中,提供了四个构造方法,每个构造方法都启动了计时器线程,同时Timer类可以保证多个线程可以共享单个Timer对象而无需进行外部同步,所以Timer类是线程安全的。但是由于每一个Timer对象对应的是单个后台线程,用于顺序执行所有的计时器任务,一般情况下我们的线程任务执行所消耗的时间应该非常短,但是由于特殊情况导致某个定时器任务执行的时间太长,那么他就会“独占”计时器的任务执行线程,其后的所有线程都必须等待它执行完,这就会延迟后续任务的执行,使这些任务堆积在一起,具体情况我们后面分析。
当程序初始化完成Timer后,定时任务就会按照我们设定的时间去执行,Timer提供了schedule方法,该方法有多中重载方式来适应不同的情况,如下:
schedule(TimerTask task, Date time):安排在指定的时间执行指定的任务。
schedule(TimerTask task, Date firstTime, long period) :安排指定的任务在指定的时间开始进行重复的固定延迟执行。
schedule(TimerTask task, long delay) :安排在指定延迟后执行指定的任务。
schedule(TimerTask task, long delay, long period) :安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
同时也重载了scheduleAtFixedRate方法,scheduleAtFixedRate方法与schedule相同,只不过他们的侧重点不同,区别后面分析。
scheduleAtFixedRate(TimerTask task, Date firstTime, long period):安排指定的任务在指定的时间开始进行重复的固定速率执行。
scheduleAtFixedRate(TimerTask task, long delay, long period):安排指定的任务在指定的延迟后开始进行重复的固定速率执行。
TimerTask
TimerTask类是一个抽象类,由Timer 安排为一次执行或重复执行的任务。它有一个抽象方法run()方法,该方法用于执行相应计时器任务要执行的操作。因此每一个具体的任务类都必须继承TimerTask,然后重写run()方法。
另外它还有两个非抽象的方法:
boolean cancel():取消此计时器任务。
long scheduledExecutionTime():返回此任务最近实际执行的安排执行时间。
二、实例
2.1、指定延迟时间执行定时任务
public class TimerTest01 {
Timer timer;
public TimerTest01(int time){
timer = new Timer();
timer.schedule(new TimerTaskTest01(), time * 1000);
}
public static void main(String[] args) {
System.out.println(“timer begin….”);
new TimerTest01(3);
}
}
public class TimerTaskTest01 extends TimerTask{
public void run() {
System.out.println(“Time’s up!!!!”);
}
}
运行结果:
首先打印:timer begin….3秒后打印:Time’s up!!!!
2.2、在指定时间执行定时任务
public class TimerTest02 {
Timer timer;
public TimerTest02(){
Date time = getTime();
System.out.println(“指定时间time=” + time);
timer = new Timer();
timer.schedule(new TimerTaskTest02(), time);
}
public Date getTime(){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 39);
calendar.set(Calendar.SECOND, 00);
Date time = calendar.getTime();
return time;
}
public static void main(String[] args) {
new TimerTest02();
}
}
public class TimerTaskTest02 extends TimerTask{
@Override
public void run() {
System.out.println(“指定时间执行线程任务…”);
}
}
当时间到达11:39:00时就会执行该线程任务,当然大于该时间也会执行!!执行结果为:
指定时间time=Tue Jun 10 11:39:00 CST 2014指定时间执行线程任务…
2.3、在延迟指定时间后以指定的间隔时间循环执行定时任务
public class TimerTest03 {
Timer timer;
public TimerTest03(){
timer = new Timer();
timer.schedule(new TimerTaskTest03(), 1000, 2000);
}
public static void main(String[] args) {
new TimerTest03();
}
}
public class TimerTaskTest03 extends TimerTask{
@Override
public void run() {
Date date = new Date(this.scheduledExecutionTime());
System.out.println(“本次执行该线程的时间为:” + date);
}
}
运行结果:
本次执行该线程的时间为:Tue Jun 10 21:19:47 CST 2014本次执行该线程的时间为:Tue Jun 10 21:19:49 CST 2014本次执行该线程的时间为:Tue Jun 10 21:19:51 CST 2014本次执行该线程的时间为:Tue Jun 10 21:19:53 CST 2014本次执行该线程的时间为:Tue Jun 10 21:19:55 CST 2014本次执行该线程的时间为:Tue Jun 10 21:19:57 CST 2014……………..
对于这个线程任务,如果我们不将该任务停止,他会一直运行下去。
对于上面三个实例,LZ只是简单的演示了一下,同时也没有讲解scheduleAtFixedRate方法的例子,其实该方法与schedule方法一样!
2.4、分析schedule和scheduleAtFixedRate
1、schedule(TimerTask task, Date time)、schedule(TimerTask task, long delay)
对于这两个方法而言,如果指定的计划执行时间scheduledExecutionTime<= systemCurrentTime,则task会被立即执行。scheduledExecutionTime不会因为某一个task的过度执行而改变。
2、schedule(TimerTask task, Date firstTime, long period)、schedule(TimerTask task, long delay, long period)
这两个方法与上面两个就有点儿不同的,前面提过Timer的计时器任务会因为前一个任务执行时间较长而延时。在这两个方法中,每一次执行的task的计划时间会随着前一个task的实际时间而发生改变,也就是scheduledExecutionTime(n+1)=realExecutionTime(n)+periodTime。也就是说如果第n个task由于某种情况导致这次的执行时间过程,最后导致systemCurrentTime>= scheduledExecutionTime(n+1),这是第n+1个task并不会因为到时了而执行,他会等待第n个task执行完之后再执行,那么这样势必会导致n+2个的执行实现scheduledExecutionTime放生改变即scheduledExecutionTime(n+2) = realExecutionTime(n+1)+periodTime。所以这两个方法更加注重保存间隔时间的稳定。
3、scheduleAtFixedRate(TimerTask task, Date firstTime, long period)、scheduleAtFixedRate(TimerTask task, long delay, long period)
在前面也提过scheduleAtFixedRate与schedule方法的侧重点不同,schedule方法侧重保存间隔时间的稳定,而scheduleAtFixedRate方法更加侧重于保持执行频率的稳定。为什么这么说,原因如下。在schedule方法中会因为前一个任务的延迟而导致其后面的定时任务延时,而scheduleAtFixedRate方法则不会,如果第n个task执行时间过长导致systemCurrentTime>= scheduledExecutionTime(n+1),则不会做任何等待他会立即执行第n+1个task,所以scheduleAtFixedRate方法执行时间的计算方法不同于schedule,而是scheduledExecutionTime(n)=firstExecuteTime +n*periodTime,该计算方法永远保持不变。所以scheduleAtFixedRate更加侧重于保持执行频率的稳定。
三、Timer的缺陷
3.1、Timer的缺陷
Timer计时器可以定时(指定时间执行任务)、延迟(延迟5秒执行任务)、周期性地执行任务(每隔个1秒执行任务),但是,Timer存在一些缺陷。首先Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终止,同时Timer也不会重新恢复线程的执行,他会错误的���为整个Timer线程都会取消。同时,已经被安排单尚未执行的TimerTask也不会再执行了,新的任务也不能被调度。故如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。
1、Timer管理时间延迟缺陷
前面Timer在执行定时任务时只会创建一个线程任务,如果存在多个线程,若其中某个线程因为某种原因而导致线程任务执行时间过长,超过了两个任务的间隔时间,会发生一些缺陷:
public class TimerTest04 {
private Timer timer;
public long start;
public TimerTest04(){
this.timer = new Timer();
start = System.currentTimeMillis();
}
public void timerOne(){
timer.schedule(new TimerTask() {
public void run() {
System.out.println(“timerOne invoked ,the time:” + (System.currentTimeMillis() – start));
try {
Thread.sleep(4000);
//线程休眠3000
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 1000);
}
public void timerTwo(){
timer.schedule(new TimerTask() {
public void run() {
System.out.println(“timerOne invoked ,the time:” + (System.currentTimeMillis() – start));
}
}, 3000);
}
public static void main(String[] args) throws Exception {
TimerTest04 test = new TimerTest04();
test.timerOne();
test.timerTwo();
}
}
按照我们正常思路,timerTwo应该是在3s后执行,其结果应该是:
timerOne invoked ,the time:1001timerOne invoked ,the time:3001
但是事与愿违,timerOne由于sleep(4000),休眠了4S,同时Timer内部是一个线程,导致timeOne所需的时间超过了间隔时间,结果:
timerOne invoked ,the time:1000timerOne invoked ,the time:5000
2、Timer抛出异常缺陷
如果TimerTask抛出RuntimeException,Timer会终止所有任务的运行。如下:
public class TimerTest04 {
private Timer timer;
public TimerTest04(){
this.timer = new Timer();
}
public void timerOne(){
timer.schedule(new TimerTask() {
public void run() {
throw new RuntimeException();
}
}, 1000);
}
public void timerTwo(){
timer.schedule(new TimerTask() {
public void run() {
System.out.println(“我会不会执行呢??”);
}
}, 1000);
}
public static void main(String[] args) {
TimerTest04 test = new TimerTest04();
test.timerOne();
test.timerTwo();
}
}
运行结果:timerOne抛出异常,导致timerTwo任务终止。
Exception in thread “Timer-0” java.lang.RuntimeException at com.chenssy.timer.TimerTest04$1.run(TimerTest04.java:25) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
对于Timer的缺陷,我们可以考虑 ScheduledThreadPoolExecutor 来替代。Timer是基于绝对时间的,对系统时间比较敏感,而ScheduledThreadPoolExecutor 则是基于相对时间;Timer是内部是单一线程,而ScheduledThreadPoolExecutor内部是个线程池,所以可以支持多个任务并发执行。
3.2、用ScheduledExecutorService替代Timer
1、解决问题一:
public class ScheduledExecutorTest {
private ScheduledExecutorService scheduExec;
public long start;
ScheduledExecutorTest(){
this.scheduExec = Executors.newScheduledThreadPool(2);
this.start = System.currentTimeMillis();
}
public void timerOne(){
scheduExec.schedule(new Runnable() {
public void run() {
System.out.println(“timerOne,the time:” + (System.currentTimeMillis() – start));
try {
Thread.sleep(4000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
},1000,TimeUnit.MILLISECONDS);
}
public void timerTwo(){
scheduExec.schedule(new Runnable() {
public void run() {
System.out.println(“timerTwo,the time:” + (System.currentTimeMillis() – start));
}
},2000,TimeUnit.MILLISECONDS);
}
public static void main(String[] args) {
ScheduledExecutorTest test = new ScheduledExecutorTest();
test.timerOne();
test.timerTwo();
}
}
运行结果:
timerOne,the time:1003timerTwo,the time:2005
2、解决问题二
public class ScheduledExecutorTest {
private ScheduledExecutorService scheduExec;
public long start;
ScheduledExecutorTest(){
this.scheduExec = Executors.newScheduledThreadPool(2);
this.start = System.currentTimeMillis();
}
public void timerOne(){
scheduExec.schedule(new Runnable() {
public void run() {
throw new RuntimeException();
}
},1000,TimeUnit.MILLISECONDS);
}
public void timerTwo(){
scheduExec.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(“timerTwo invoked …..”);
}
},2000,500,TimeUnit.MILLISECONDS);
}
public static void main(String[] args) {
ScheduledExecutorTest test = new ScheduledExecutorTest();
test.timerOne();
test.timerTwo();
}
}
运行结果:
timerTwo invoked …..timerTwo invoked …..timerTwo invoked …..timerTwo invoked
作者: chenssy
出处: http://www.cnblogs.com/chenssy/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
C++的反思
来自:Skywind Inside
作者:skywind
链接:http://www.skywind.me/blog/archives/1398
最近两年 C++又有很多人出来追捧,并且追捧者充满了各种优越感,似乎不写 C++你就一辈子是低端程序员了,面对这种现象,要不要出来适时的黑一下 C++呢?呵呵呵。
咱们要有点娱乐精神,关于 C++的笑话数都数不清:
笑话:C++是一门不吉祥的语言,据说波音公司之前用ADA为飞机硬件编程,一直用的好好的,后来招聘了一伙大学生,学生们说我靠还在用这么落后的语言,然后换成C++重构后飞机就坠毁了。
笑话:什么是C++程序员呢?就是本来10行写得完的程序,他非要用30行来完成,并自称“封装”,但每每到第二个项目的时候却将80%打破重写,并美其名曰 “重构”。
笑话:C容易擦枪走火打到自己的脚,用C++虽然不容易,但一旦走火,就会把你整条腿给炸飞了。
笑话:同时学习两年 Java的程序员在一起讨论的是面向对象和设计模式,而同时学习两年 C++的程序员,在一起讨论的是 template和各种语言规范到底怎么回事情。
笑话:教别人学 C++的人都挣大钱了,而很多真正用 C++的人,都死的很惨。
笑话:C++有太多地方可以让一个人表现自己“很聪明”,所以使用C++越久的人,约觉得自己“很聪明”结果步入陷阱都不知道,掉坑里了还觉得估计是自己没学好 C++。
笑话:好多写了十多年 C++程序的人,至今说不清楚 C++到底有多少规范,至今仍然时不时的落入某些坑中。
笑话:很多认为 C++方便跨平台的人,实际编写跨平台代码时,都会发现自己难找到两个支持相同标准的 C++编译器。
—————
Q:那 C++为什么还能看到那么多粉丝呢?
A:其实是因为 Windows,因为 Windows的兴起带动了 C++,C++本来就是一门只适合开发 GUI的语言。
Q:为何 C++只适合开发 GUI呢?
A:你看 Unix下没有 GUI,为啥清一色的 C呀?所有的系统级问题都能在 C里找到成熟的解决方案,应用级问题都能用其他高级语言很好地解决,哪里有 C++什么事情呀?
Q:你强词夺理,Unix下也有 C++的项目呀。
A:有,没错,你任然可以用任何语言编写任何糟糕的代码。
Q:别瞎扯了,你都在说些什么?连C++和 Windows 都扯到一起去了。
A:回想下当年的情景,一个大牛在教一群初学者如何编程。一边开发一边指着屏幕上说,你看,这是一个 Button,我们可以用一个对象来描述它,那是一个 panel我们也可以用一个对象来描述它,并且你们有没有发现,其实 Button和 Panel是有血缘关系的,你们看。。。这样就出来了。。。。下面的学生以前都是学着学校落后的教材,有些甚至还在用 turboc的 bgi库来画一些点和圆。哪里见过这么这么华丽的 Windows 界面呀。大牛说的话,象金科玉律一样的铭刻在自己幼小的心理。一边学着 Windows,一边发现,果然,他们都需要一个基类,果然,他们是兄弟关系,共同包含一些基本属性,可以放到基类去。他们越用越爽,潜意识里觉得因为 C++这么顺利的帮他们解决那么多界面问题,那看来 C++可以帮他们解决一切问题了。于是开发完界面以后,他们继续开发,当他们碰到各种设计问题时,反而认为肯定自己没有用好 C++。于是强迫自己用下去,然后就完蛋了。
(点击 more展开)
—————
关于 C++的笑话我有一箩筐,各位 C++粉用不着对号入座。言归正传,为什么要黑 C++呢?谈不上黑不黑,我从94年开始使用 C++(先前是 C 和 Pascal),一路看着 C++成长壮大,用 C++写过的代码,加起来应该超过 10MB了吧,C++的各种宝典我也都读过,一直到 2004年开始切回 C,主要原因是发现很多没法用 C++思路继续解决下去的问题,或者说用 C++思路解决下去会很糟糕的问题。
那时候(2004-2005)正是 C++满天飞的时候,言必称 C++,用必用模版,我跳出来说你们醒醒吧,别过火了,这个世界并不是都是抽象数据结构和算法就可以描述清楚的。于是很多人激动的跳出来说:“你没领会到 C++精髓,你根本都不会用 C++”。我问他们:“语言是用来解决问题的,如果一个语言学了三四年都会经常掉沟里,算好语言么?如果编写十多年 C++的程序员都很难掌握得了,这算好语言么”。他们又说:“语言是死的,人是活的”。
我记得当时一位国内 C++大牛,为了纠正我的 “错误观点”,给我看过他写的一套十分强大的库,我打开一看,倒吸了一口冷气,全部是 .h文件。我只能回他三个字:“你牛逼”。当然这是一个极端的例子,那家伙后来终于也开始把 .h里面的东西逐步挪到 .cpp里面了,这是好事。
当时和云风在一家公司,2004年新人培训时,他给新人布置了一个实现内存分配器的作业,批改作业的时候,他经常边看边问人家,“不够C++呀,你能不能百分之百OOP?”,“1%的 C都不要留”。我当时在公司内部邮件列表里面发过关于 C++的问题,大部分人都表示:“你看没有C++我们怎么写3D引擎呢?”。我跟他们讲:“John Carmack直到 Quake3都还在用着 ANSI C,后来因为不得不支持 D3D,改用 C++了。为啥 C不能写 3D引擎了?”。他们告诉我:“你看,Point,就是个对象,Matrix也是个对象,那么多 Vector的代数计算,用 C++的算术重载是多么美妙的事情,三维世界就是对象的世界。”。
确实当时客户端 GUI的话,只有 C++,图形引擎也只有 C++,这两个正是C++最强的地方,所以我也没和他们争辩,强迫他们承认 C也可以很漂亮的写图形,而且C写的可以写的很优雅。我又不是闲着没事情,何必去质疑人家的核心价值观呢,呵呵。当年我正在接手一个 C++项目,代码超过 800KB,每次崩溃都需要花费很长时间去定位,项目中大量的前后依赖,改一个地方,前后要看好几处,一处遗漏,整个系统就傻逼了。我开始重构后,画了两个星期,将性能敏感的核心部分剥离出来用 C实现(代码量仅 200KB),然后导出 Python接口,用Python来完成剩下的部分,整个脚本层代码量只有 150KB。整个世界清爽了,整个 C++项目原来的工期为 2个程序员四个月,我一个人重构的时间加起来就 1.5个月,而且代码量比远来少了两倍还多,各种奇特的 BUG也一扫而尽。我看看左边的 800KB一团乱麻的 C++代码,再看看右边整洁的 300多 KB 纯 C + Python,琢磨着,这个项目干嘛不一开始就这么做?
跨语言接口
现代项目开发,不但需要更高的性能,而且需要更强大的语言描述能力。而 C++正处在一个尴尬的地方,比底层,它不如 C能够精确的控制内存和硬件,各种隐式构造让你防不胜防;比描述能力,比快速业务开发和错误定位,它又赶不上 Python, Ruby, Lua等动态语言,处于东线和西线同时遭受挤压和蚕食的地步。
很快,2006-2007年左右,其他项目组各种滥用 C++的问题开始显现出来:当时脚本化已经在工程实践中获得极大的成功,然而某些项目一方面又要追求 100%的 C++,另一方面又需要对脚本导出接口,他们发现问题了,不知道该怎么把大量的 C++基础库和接口导给 Lua。
C的接口有各种方便的方式导给脚本,然而整个项目由一群从来就不消于使用脚本的cpp大牛开发出来,当他们要吧cpp类导出接口给脚本时,他们设计了一套牛逼的系统,lua自动生成机器码,去调用c++的各种类,没错,就是c++版本的cffi或者ctypes。他为调用vc的类写了一套机器码生产,又为调用gcc的类写了一套代码生成。那位cpp大牛写完后四处炫耀他的成果,后来他离职了,项目上线一而再再而三的出现无可查证的问题,后来云风去支援那个项目组,这套盘根错节的c++项目,这套盘大的代码自生成系统深深的把他给恶心到了。后来众所周知云风开始反C++,倡导回归C了,不知道是否和这个项目有关系。
于是发现个有趣的现象,但凡善于使用脚本来提高工程效率的人,基本都是C加动态语言解决大部分问题(除了gui和图形),但凡认为c++统治宇宙的人很多都是从来没使用过脚本或者用了还不知道该怎样去用的人。
凭借这样的方法,我们的产品同竞争对手比拼时,同样一个功能,同样的人力配置,竞争对手用纯C++要开发三月,我们一个月就弄出来了,同样的时间,对手只能试错一次,我们可以试错三次。后来,据我们招聘过来的同事说,竞争对手也开始逐步降低 C++的比例,增加 java的比例了,这是好事,大家都在进步嘛。
ABI的尴尬
ABI级别的 C++接口从来没有标准化过,以类为接口会引入很多隐藏问题,比如内存问题,一个类在一个库里面实例化的,如果再另外一个库里面释放它们就有很多问题,因为两个动态库可能内存管理系统是不一样的。你用这里的 allocator分配一块内存,又用那里的 allocator去释放,不出问题才怪。很多解决方法是加一个 Release 方法(比如 DX),告诉外面的人,用完的时候不要去 delete,而是要调用 Release。
项目写大了各个模块隔离成动态库是很正常的,而各种第三方库和自己写的库为追求高性能引入特定的内存管理机制也是很正常的。很多人不注意该调用release的地方错写成delete就掉沟里去了。更有胜者跨 ABI定义了很多inline方法的类,结果各种隐式构造和析构其实在这个库里生成,那个库里被析构,乱成一团乱麻。C就清晰很多,构造你就调用fopen,析构你就fclose,没有任何歧义。其实C++的矛盾在于一方面承认作为系统级语言内存管理应该交给用户决定,一方面自己却又定义很多不受用户控制的内存操作行为。所以跨 ABI层的c++标准迟迟无法被定义出来,不是因为多态 abi复杂,而是因为语言逻辑出现了相互矛盾。为了弥补这个矛盾,C++引入了operator new,delete,这new/delete重载是一个补丁并没从逻辑上让语言变得完备,它的出现,进一步将使用者拖入bug的深渊。
其实今天我们回过头去看这个问题,能发现两个基本原则:跨abi的级别上引入不可控的内存机制从语言上是有问题的,只能要靠开发者约定各种灵巧的基类和约定开发规范来解决,这个问题在语言层是解决不了的;其次你既然定义了各种隐式构造和析构,就该像java活着动态语言一样彻底接管内存,不允许用户再自定义任何内存管理方法,而不是一方面作为系统极语言要给用户控制的自由,一方面自己又要抢着和用户一起控制。
因此对象层 ABI接口迟迟无法标准化。而纯 C的 ABI不但可以轻松的跨动态库还能轻松的和汇编及各类语言融合,不是因为C设计多好,而是C作为系统层语言没有去管它不该管的东西。当年讨论到这个话题时 C++大牛们又开始重复那几句金科玉律来反驳我:“语言只是招式,你把内功练好,就能做到无招胜有招,拿起草来都可以当剑使,C++虽然有很多坑,你把设计做好不那么用不就行了”。我说:本来应该在语言层解决好的事情,由于语言逻辑不完备,将大量问题抛给开发者去解决极大的增加了开发者的思维负担,就像破屋上表浆糊一样。你金庸看多了吧,武术再高,当你拿到一把枪发现子弹不一定往前射,偶尔还会往后射时,请问你是该专心打敌人呢?还是时刻要提防自己的子弹射向自己?
系统层的挫败
C++遭受挫败是进军嵌入式和操作系统这样靠近硬件层的东西。大家觉得宇宙级别的编程语言,自然能够胜任一切任务,很快发现几个问题:
●无法分配内存:原来用 C可以完全不依赖内存分配,代码写几千行一个 malloc没有都行。嵌入式下处理器加电后,跳到特定地址(比如起始地址0),第一条指令一般用汇编来写,固定在0地址,就是简单初始化一下栈,然后跳转到 C语言的 start函数去,试想此时内存分配机制都还没有建立,你定义了两个类,怎么构造呀?资源有限的微处理器上大部分时候就是使用一块静态内存进行操作。C++写起来写爽了,各种隐式构造一出现,就傻了。
●标准库依赖:在语言层面,C语言的所有特性都可以不用依赖任何库就运行,这为编写系统层和跨平台跨语言代码带来了很方便的特性。而C++就不行,我要构造呀,我要异常呀,你为啥不能给我强大的运行时呢?什么你还想用 stl?不看看那套库有多臃肿呀(内存占用,代码尺寸)。
●异常处理问题:底层开发需要严格的处理所有错误返回,这一行调用,下一行就判断错误。而异常是一种松散的错误处理方式,应用层这么写没问题,系统层这么写就很狼狈了。每行调用都try一下和 C的调用后if判断结果有什么区别?C++的构造函数是没有返回值的,如果构造内部出错,就必须逼迫你catch构造函数的异常,即便你catch住了,构造异常的时候当然会自动触发相关内部对象的析构,但是有很多并没有析构的资源(比如系统资源,比如C接口的资源,他们都没有一个析构),整个过程是很难控制的,此时这个实例是一个半初始化实例,你该怎么处理它呢?于是有人把初始化代码移除构造函数,构造时只初始化一下变量,新增加一个带返回的init函数,这样的代码写的比C冗余很多。何况硬件中断发生时,在你不知道的情况下,同事调到一些第三方的库,你最外层没有把新的exception给 catch住,这个exception该往哪里抛呀?内存不够的时候你想抛出一个 OutOfMemoryException,可是内存已经不够了,此时完全无能力构造这个异常又该怎么办呢?
●处理器兼容:C++的类依赖基地址+偏移地址的寻址方式,很多非 Intel系列的微处理器上只有简单的给定地址寻址,不支持这样一条语句实现BASE+OFFSET的寻址,很多C++代码编译出来需要更多的指令来运算地址,导致性能下降很多,得不偿失。
●隐式操作问题:C的特点是简单直接,每行语句你都能清楚的知道会被翻译成什么样子,系统会严格按照你的代码去执行。而用C++,比如 str1 = str2 + “Hello” + str3; 这样的语句,没几个人真的说得清楚究竟有多少次构造和拷贝,这样的写法编写底层代码是很不负责任的,底层需要更为精细和严格的控制,用C语言控制力更强。
当然,说道这里很多人又说,“C++本来就是 C的超集,特定的地方你完全可以按照C的写法来做呀。没人强迫你构造类或者使用异常呀”,没错,按 Linus的说法:“想要用 C++写出系统级的优秀的可移植和高效的代码,最终还是会限于使用 C本身提供的功能,而这些功能 C都已经完美提供了,所以系统层使用 C的意义就在于在语言层排除 C++的其他特性的干扰”。
很多人都记得 Linus在 2007年因为有人问 Git为什么不用 C++开发炮轰过一次C++。事实上2004年 C++如日中天的时候,有人问 Linux内核为何不用 C++开发,他就炮轰过一次了:
– 整套 C++异常处理系统是 “fundamentally broken”。特别对于编写内核而言。
– 任何语言或编译器喜欢在你背后隐藏行为(如内存分配)对于开发内核并不是一个好选择。
– 任然可以用 C来编写面向对象代码(比如文件系统),而不需要用 C++写出一坨屎来。
总得来说,对任何希望用 C++来开发内核的人而言,他们都是在引入更多问题,无法象 C一样清晰的看到自己到底在写什么。
C++粉丝们在C++最火热的时候试图将 C++引入系统层开发,但是从来没有成功过。所以不管是嵌入式,还是操作系统,在靠近硬件底层的开发中,都是清一色的 C代码,完全没有 C++的立足之地。
应用层的反思
STL出来后,给人一种 C++可以方便开发应用层逻辑的错觉。由于很多语言层不严密的事情,让STL来以补丁的方式完成,于是很多以为可以象写 java一样写 C++的初学者落入了一个个的坑中。比如 list.size(),在 Windows下vc的 stl是保存了 list的长度的,size()直接 O(1)返回该变量,而在gcc的 stl中,没有保存 list长度,size()将搜索所有节点,O(n)的速度返回。
由于语言层不支持字符串,导致 std::string实现十分不统一,你拷贝构造一个字符串,有的实现是引用,才用 copy-on-write的方法引用。有的地方又是 new,有的实现又是用的内存池,有的实现线程安全,有的实现线程不安全,你完全没法说出同一个语句后面到底做了些什么(见孟岩的《Linux之父话糙理不糙》)。
再比如说我想使用 hash_map,为了跨平台(当你真正编写跨平台代码时,你很难决定目标编译器和他们的版本,想用也用不了 unordered_map),我很难指出一种唯一声明 hash_map的方法,为了保证在不同的编译器下正常的使用 hash_map,你不得不写成这样:
#ifdef __GNUC__
#ifdef __DEPRECATED
#undef __DEPRECATED
#endif
#include <ext/hash_map>
namespace stdext { using namespace __gnu_cxx; }
namespace __gnu_cxx {
template<> struct hash< std::string > {
size_t operator()( const std::string& x ) const {
return hash< const char* >()( x.c_str() );
}
};
}
#else
#ifndef _MSC_VER
#include <hash_map>
#elif (_MSC_VER < 1300)
#include <map>
#define IHAVE_NOT_HASH_MAP
#else
#include <hash_map>
#endif
#endif
#ifdef __GNUC__
using namespace __gnu_cxx;
typedef hash_map<uint32_t, XXXX*> HashXXXX;
#else
using namespace stdext;
typedef hash_map<uint32_t, XXXX*> HashXXXX;
#endif
如果有更好的跨平台写法,麻烦告诉我一下,实在是看不下去了。一个基础容器都让人用的那么辛苦,使得很多 C++程序员成天都在思考各种规范,没时间真正思考下程序设计。
由于语言层要兼容 C,又不肯象 C一样只做好系统层的工作,导致当 C++涉足应用层时,没法接管内存管理,没法支持语言层字符串,没法实现语言层基础容器。所以需要借助一些 stl之类的东西来提供便利,但 stl本身又是充满各种坑的。且不说内存占用大,程序体积大等问题,当编译速度就够呛了。所以为什么 C++下面大家乐意重复造轮子,实现各种基本容器和字符串,导致几乎每个不同的 C++项目,都有自己特定的字符串实现。就是因为大家踩了坑了,才开始觉得需要自己来控制这些细节。stl的出发点是好的,但是只能简单小程序里面随便用一下,真是大项目用,stl就容易把人带沟里了,所以很多大点的 C++项目都是自己实现一套类似 STL的东西,这难道不是违背了 stl设计的初衷了么?
语言层的缺失,让大家为了满足业务开发的快速迭代的需求,创造了很多很基础的设计灵巧的基类,来提供类似垃圾回收,引用计数,copy-on-write,delegate,等数不胜数的功能。每个项目都有一系列 BaseObject 之类的基础类,这样就引入一个误区,两年后你再来看你的代码,发现某个 BaseObject不满足需求了,或者你和另外一个项目 merge代码时,需要合并一些根本属性。图形和GUI这些万年不变的模型还好,应用类开发千变万化,一旦这些设计灵巧的基类不再适应项目发展时,往往面临着全面调整的代价。
打开一个个 C++大牛们 blog,很多地方在教你 std::string的原理,需要注意的事项。map的限制,vector的原理,教你如何实现一个 string。这就叫 “心智负担”,分散你的注意力,这是其他语言里从来见不到的现象。战士不研究怎么上前线杀敌,天天在琢磨抢和炮的原理,成天在思考怎么用枪不会走火,用炮不会炸到自己,这战还怎么打?
所以此后几年,越来越多的人开始反思前两年C++过热所带来的问题,比如高性能网络库 ZeroMQ作者 Martin Sustrik 的:《为什么我希望用C而不是C++来实现ZeroMQ》,比如云风的《云风的 BLOG: C 的回归》,比如引起热议的《Why C++ Is Not “Back”》。
全面被代替
2008年以后,行业竞争越来越激烈,正当大家一边苦恼如何提高开发效率,一边掉到C++的各种坑里的时候,越来越多的应用开发方案涌现出来,他们都能很好的代替 C++。各行各业的开发者逐步相见恨晚的发现了各种更加优秀的方案:需要底层控制追求性能的设计,大家退回到 C;而需要快速迭代的东西大家找到各种动态语言;介于性能和开发速度之间的,有java,知乎上好像很多黑java的,语言是有不足,但是比起C++好很多,没那么多坑,真正考虑面向对象,真正让人把心思放在设计上。所以再黑也不能挡住 java在 tiobe上和 C语言不是第一就是第二的事实,再黑也挡不住 java在云计算,分布式领域的卓越贡献。
所以2005年以后,C++处在一个全面被代替的过程中:
●底层系统:进一步回归 C语言,更强的控制力,更精确的操作。
●网页开发:2006年左右,C++和 fastcgi就被一起赶出 web世界了。
●高性能服务:varnish, nginx, redis 等新的高性能网络服务器都是纯C开发的。
●分布式应用:2007年左右, C++被java和其他动态语言彻底赶跑。
●游戏服务端:2008年后进一步进化为 C 和 脚本,完全看不到胖C++服务端了。
●并行计算:2010年后,go, scala, erlang;而能方便同go接口的,是 C不是C++。
●游戏引擎:没错 C++和脚本,但是这年头越来越多的开源引擎下,引擎类需求越来越少。
●游戏逻辑:脚本
●多媒体:SDL纯C,ffmpeg是纯 C,webrtc的核心部分(DSP, codec)是纯C的。
●移动开发:早年C++还可以开发下塞班,现在基本被 java + objc + swift 赶跑了。
●桌面开发:Qt+Script, C#等都能做出漂亮的跨平台界面。且界面脚本化趋势,不需要C++了。
●网页前端:JavaScript, Html5, Flash
●操作系统:FreeBSD, Open Solaris, Linux, RTOS, Darwin(OS X 底层),都是纯 C
●虚拟技术:qemu / kvm (云计算的基石)纯 C,Xen 纯 C
●数据库:MySQL (核心纯C,外围工具 C++),SQLite 纯 C, PostgreSQL / BDB / unqlite 纯C
●编译器:C/C++并存,不过编译器用脚本写都没关系,我还在某平台用 java写的 C/C++编译器
●大数据:kafka, hadoop, storm, spark 都使用 Java / Jvm 系列技术
●云存储:openstack swift python, hdfs java, 还有好多方案用 go
可以看出,即便 C++的老本行,GUI和图形(确实也还存在一些短期内 C++无法替代的领域,就像交易系统里还有 COBOL一样),这年头也面临的越来越多的挑战,比如新发布的 Rust (如何看待 Rust 的应用前景? – 知乎用户的回答)。可以发现,开发技术多元化,用最适合的技术开发最适合的应用是未来的趋势。而为这些不同的技术编写高性能的可控的公共组件,并轻松的和其他语言接口,正是 C语言的强项。所以不管应用层语言千变万化,对系统级开发语言C的需求还是那么的稳定,而这个过程中,哪里还有 C++的影子呢?
话题总结
所以说未来的趋势是:C x 各种语言混搭 的趋势,从TIOBE上 C++的指数十年间下跌了三倍可以看出,未来还会涌现出更多技术来代替各个角落残存的C++方案,C++的使用情况还会进一步下降。所以题主问学习纯C是否有前途,我觉得如果题主能够左手熟练的掌握 C语言,培养系统化的思维习惯和精确控制内存和硬件的技巧;右手继续学习各种新兴的开发技术,能够应对各个细分领域的快速开发,碰到新问题时能左右开弓,那么未来工作上肯定是能上一个大台阶的。至于C++ 嘛,有时间看看就行,逼不得已要维护别人代码的情况下写两行即可。
故事分享
古代用弓箭进行远距离攻击时,对射手要求较高,瞄准难度大,需要一直使劲保持准心。战斗中一个弓箭手开弓二十次就需要比较长的休息时间。弩的威力远胜于弓,秦弩的制造就如现代的自动步枪一般精密无二,它既可以延长射击,又可以精确瞄准。弩箭的发射速度更是弓箭的数倍,威力惊人。因为弩的操作非常简单,不需要射击技巧,平民很容易掌握它的使用方法。秦国靠着弩兵,在战争中取得了不少优势,被人称为 “虎狼之师”。
日本投降时,天皇下罪己诏。很多士兵不愿意相信这时真的,找种种理由拒绝相信。有的士兵甚至以为天皇的广播是敌人诱降的把戏,于是躲到丛林里继续三五成群的收集情报,袭击可以攻击的目标,等待上司来给他们下达新命令。直到好几年后看到周围的人都穿着日常的便装了,而来巡山的 “敌人” 也从士兵变为了巡逻队,他们都还觉得这是敌人的伪装。而同时,德国战败时,最后的党卫军一直战斗到 1957年才肯投降。
—————————————–
很多人觉得Java慢,C++快Java 10倍以上已经是上世纪的事情了,现代的 Java 只比 C/C++慢 70%,C++连1倍都快不了 Java。也不要觉得动态语言慢,javascript只比C/C++慢 2.7倍。luajit只比 C++慢 5.8倍。在 jit技术发展的今天,C++在性能上离动态语言/java的差距越来越小,可易用性和生产效率上的差距,却和动态语言/java 比起来越来越大。
—————————
最后,补充一张图:
机器学习中的梯度下降法
来自: Datartisan数据工匠(微信号: shujugongjiang)
链接:http://datartisan.com/article/detail/99.html
最优化问题是机器学习算法中非常重要的一部分,几乎每一个机器学习算法的核心都是在处理最优化问题。
- 什么是梯度下降法?
- 如何将梯度下降法运用到线性回归模型中?
- 如何利用梯度下降法处理大规模的数据?
- 梯度下降法的一些技巧
让我们开始吧!
想象一个你经常用来吃谷物或储存受过的大碗,成本函数的形状类似于这个碗的造型。
梯度下降法的过程
梯度下降法首先需要设定一个初始参数值,通常情况下我们将初值设为零(coefficient=0coefficient=0),接下来需要计算成本函数 cost=f(coefficient)cost=f(coefficient) 或者 cost=evaluate(f(coefficient))cost=evaluate(f(coefficient))。然后我们需要计算函数的导数(导数是微积分的一个概念,它是指函数中某个点处的斜率值),并设定学习效率参数(alpha)的值。
coefficient=coefficient−(alpha∗delta) coefficient=coefficient−(alpha∗delta) 重复执行上述过程,直到参数值收敛,这样我们就能获得函数的最优解。
你可以看出梯度下降法的思路多么简单,你只需知道成本函数的梯度值或者需要优化的函数情况即可。接下来我将介绍如何将梯度下降法运用到机器学习领域中。
批量梯度下降法是机器学习领域中常见的一种梯度下降方法。
对于大规模数据来说,随机梯度下降法的收敛速度明显高于其他算法,通常情况下你只需要一个小的迭代次数就能得到一个相对较优的拟合参数。
- 绘制成本函数随时间变化的曲线:收集并绘制每次迭代过程中所得到的成本函数值。对于梯度下降法来说,每次迭代计算都能降低成本函数值。如果无法降低成本函数值,那么可以尝试减少学习效率值。
- 学习效率:梯度下降算法中的学习效率值通常为0.1,0.001或者0.0001。你可以尝试不同的值然后选出最佳学习效率值。
- 标准化处理:如果成本函数不是偏态形式的话,那么梯度下降法很快就能收敛。隐蔽你可以事先对输入变量进行标准化处理。
- 绘制成本均值趋势图:随机梯度下降法的更新过程通常会带来一些随机噪声,所以我们可以考虑观察10次、100次或1000次更新过程误差均值变化情况来度量算法的收敛趋势。
- 最优化理论是机器学习中非常重要的一部分。
- 梯度下降法是一个简单的最优化算法,你可以将它运用到许多机器学习算法中。
- 批量梯度下降法先计算所有参数的导数值,然后再执行参数更新过程。
- 随机梯度下降法是指从每个训练实例中计算出导数并执行参数更新过程。
你不需要Hadoop做数据分析的10个理由 —— 使用之前必须测试其他替代品
来自:开源中国社区
链接:http://www.oschina.net/translate/hadoop-when-to-use
原文:http://www.fromdev.com/2013/06/hadoop-when-to-use.html
为你的业务使用大数据技术是一个非常有吸引力的事情,现在Apache Hadoop使得它更加吸引人了。
Hadoop是一个大规模可伸缩的数据存储平台,被用作许多大数据项目的基础。
Hadoop很强大,但是它有一个很陡峭的学习曲线,需要公司在时间和其他资源上作大量的投资。
如果正确地应用它,对你的公司来说,Hadoop可以成为一个真正的游戏规则改变者,但它存在很多被错误使用的可能。
另一方面,许多企业(不像是谷歌、Facebook或Twitter)都没有真正的“大数据”来需要用一个巨大的hadoop集群分析事物,然而 hadoop 这个流行语却吸引着他们。
如大卫惠勒所说的:“所有计算机科学的问题都可以用另一个间接的中间层来解决”。 Hadoop提供了这样一种间接层;作为一个软件架构师,当你的最高管理层对一些流行语有很不专业的偏颇认识时,也许真的很难采取正确的决定。
在本文中,我想要建议“应在投资到Hadoop之前尝试一些替代品”。
了解你的数据
总体数据的大小
Hadoop被设计用来在大型数据集上能进行有效的工作。简单给点提示:
- Hadoop有一个专为大尺寸文件(如几G)设计的文件系统(HDFS)。因此,如果你的数据文件尺寸只是几M的话,建议你合并(通过zip或tar)多个文件到一个文件中,使其尺寸在几百M到几G范围内。
- HDFS把大文件们拆分存储到以64MB或128MB或更大的块单元中。
如果你的数据集相对较小,那它就不会是hadoop的巨型生态系统的最佳使用之地。这需要你去对你的数据比以往理解更多一些,分析需要什么类型的查询,看看你的数据是否真得“大”。
另一方面,只是通过数据库的大小来测量数据可能是骗人的,因为你的计算量可能会更大。 有时你可能会做更多的数学计算或分析小数据集的排列,这些可以远远大于实际的数据。所以关键是要“了解你的数据,并且很清楚它”。
数据增长数度(增长速率)
你的数据仓库或是其它数据源中可能拥有数个TB的数据。然而,在建立 Hadoop 集群前,你必须考虑到数据的增长。
向数据分析师问几个简单的问题:
- 数据增长的有多快?这个数据增长的步伐很快么?
- 数月或数年之后,这个数据将会达到什么样的尺寸?
许多公司的数据增长是以数年而非数月或数日计算的。如果你的数据增长数度非常快,我见建议你考虑一下归档及清理技术(将在本文后面的内容中详述),而非立即上马 Hadoop 集群。
如何减少你的数据量
如果你觉得你的数据实在是太大了,你可以考虑使用下面的方法将数据减少到相对可控的规模上。下面的几个选项都已经被业内成功使用多年。
归档
数据归档是将陈旧数据移动到一个独立数据储存器以长期保留(如果需要)的过程。
这需要对数据、对应用使用情况的充分了解。处理大数据的电子商务公司在现场数据库中保存近期3个月的订单细节数据,而早期订单则保存在一个独立的数据存储器中。
这个方法也可以使用到你的数据仓库中。你可以保存近期的数据以便更快的查询和报告,而将访问频率较低的数据保存在一个其它不同的存储设备中。
考虑清除数据
我们忙于收集数据时经常并不真正确定我们应该保留多少。如果你存储大量可能不是很有用的数据,它就会拖慢你近期数据的处理。弄清你的业务需求,看看是否可以删除旧的数据,把从那些数据分析的趋势存储起来以供后用。这不仅会节省你的空间,而且还可以在分析近期数据时帮助你加快速度。
对这种情况的一个常见的最佳实践是在您的数据仓库中有一些标准列,像创建日期,创建者,更新日期,更新者。现在根据这些列创建一个每日/每月的cron作业,用它清除你不想在你的数据仓库中看到的时段的数据。清除数据的逻辑基于你的领域可能不同,因此在实施它之前应作一些考虑。
如果您正在使用一个归档工具,它也可能是通过很轻松地配置就能清除无用的存档数据。
所有的数据都不重要
你可能受不了为你的业务保留所有数据的诱惑。你的数据有各种各样的来源,比如日志文件、现场交易、供应商整合、ETL工作、营销活动数据等等。但你应该知道,不是所有的数据都是关键业务,把它们都保存在一个数据仓库中可能不是很有帮助反而有害。在它们被存储到你的数据仓库之前,应从源头上过滤不需要的数据。如果你真需要在你的数据库的表里每一列存储和分析那些数据,就准备好发疯吧。
想好你想收集哪些作为数据
假设你进入一个在线视频编辑的业务。你想保存你的用户在每个视频上做的全部更改吗?这会产生巨大的体积。当你感觉到你的数据仓库可能无法处理它的情况下,你可能需要考虑只存储元数据。视频编辑是一个很可能的例子,不过它可能适用于许多其他与你存储数据相关的信息。
一般来说,如果你有一些有关系的数据,你就有机会从多个来源得到它们,而且不是所有的都需要存储在你的数据仓库中。
更智能的分析
聘请理解业务的分析师
现在,你可能已经明白“了解数据”对于有效地管理它们来说是非常重要的。相信我,当你觉得我已经试了所有这些东西时,这一步会帮到你。是时候让我们进入一个如Hadoop这样的大数据解决方案中了。
如果你的数据分析师不懂应从中提取什么出来,Hadoop就将几乎无用。应寄希望于那些理解业务的人。鼓励他们做实验和学习新的方法来看待相同的数据。找出哪些可以与现有基础设施取得唾手可得的收益。
为制订决策使用统计抽样
统计抽样是研究人员和数学家为了对大型数据推断合理结论而使用的一种非常古老的技术。
通过执行一个统计的样本,我们的体积可以极大地减少。不用跟踪数百万或数十亿的数据点,我们只需要随机挑选几千或几百个即可。
该技术不能提供准确的结果,但是它可以被用于对一个大型数据集获得高水平的理解。
定标技术
你真地把关系数据库的处理发挥到极致了吗?
在你真去探索其他技术之前,我希望你去看看关系型数据库是否能够处理它。人们使用关系数据库已经很久了,已经托管了一些几T字节大小的数据仓库。在你决定进入hadoop之前,你可以对关系数据库尝试以下方法。
数据分区
数据分区就是逻辑上和/或物理上把数据划分成一些更容易维护或访问的部分的过程。分区支持最流行的开放源代码关系数据库(MySQL 分区 和 Postgres 分区 )。
对关系数据库尝试数据库分片的方法
数据库分片可以作为对关系数据库的处理速度发挥到极限的最后一个手段。这种方法可以应用于你可以逻辑上分离数据到不同的节点,并在你的分析中有更少的交叉节点连接的时候。在web应用程序中,一个常见的分片方法是基于把用户和所有与一个用户相关的信息存储在一个节点上来确保最佳的速度。
分片并不容易,如果你有很多复杂的关系,并且没有简单的方法来分离数据到不同的节点上,这个方案可能不适合你。如果你的应用需要有很多交叉节点连接,分片的打算可能会失败。
结论
我曾在不同的公司被高层管理人员要求把Hadoop作为一个可选项去做某些事。要说服他们总是很难,但是当我把这个信息告诉他们后,他们不得不三思而后行。我很幸运,能为我工作的这些公司节省一些钱。
如果你发现为了扩大你的关系数据库,你已经尝试了所有可能的选项,这才是你应该开始考虑建立一个Hadoop集群的时候。
首先,您可能应该使用cloudera提供的虚拟机镜像。它们对于在你现有的基础设施上使用hadoop做快速的概念证明真的是很方便。
你对大数据有何经验?请在评论部分与我们分享。