在Python中实现的所有算法(用于教育)
这些实现仅用于学习目的。因此,它们的效率可能低于Python标准库中的实现
地址:https://github.com/TheAlgorithms/Python
投稿指南
在您投稿之前,请阅读我们的投稿指南
社区频道
我们在吉特路上!请加入我们
算法列表
请参阅我们的目录
这些实现仅用于学习目的。因此,它们的效率可能低于Python标准库中的实现
地址:https://github.com/TheAlgorithms/Python
在您投稿之前,请阅读我们的投稿指南
我们在吉特路上!请加入我们
请参阅我们的目录
算法 | 操作系统 | 网络 | 面向对象 | 数据库 | Java | 系统设计 | 工具 | 编码实践 | 后记 |
---|---|---|---|---|---|---|---|---|---|
:pencil2: | :computer: | :cloud: | :art: | :floppy_disk: | :coffee: | :bulb: | :wrench: | :watermelon: | :memo: |
笔记内容按照中文文案排版指北进行排版,以保证内容的可读性.
本仓库的内容不是将网上的资料随意拼凑而来,除了少部分引用书上和技术文档的原文(这部分内容都在末尾的参考链接中加了出处),其余都是我的原创.在您引用本仓库内容或者对内容进行修改演绎时,请署名并以相同方式共享,谢谢.
转载文章请在开头明显处标明该页面地址,公众号等其它转载请联系zhengyc101@163.com
了解如何设计大型系统
为系统设计面试做准备
学习如何设计可伸缩的系统将帮助您成为一名更好的工程师
系统设计是一个宽泛的话题。网上有大量关于系统设计原则的资源。
此repo是一个有组织的资源集合,可帮助您了解如何大规模构建系统
这是一个不断更新的开放源码项目
欢迎投稿!
除了对面试进行编码外,系统设计在许多科技公司的技术面试流程中也是必不可少的组成部分
练习常见的系统设计面试问题,并将您的结果与示例解决方案(讨论、代码和图表)进行比较
面试准备的其他主题:
提供的Anki抽认卡套装使用间隔重复来帮助您记住关键的系统设计概念
非常适合在旅途中使用
正在寻找资源来帮助您准备编码面试吗?
请查看姊妹版repo交互式编码挑战,其中包含额外的Anki幻灯片:
向社区学习
请随时提交拉取请求以提供帮助:
需要润色的内容正在开发中
查看投稿指南
各种系统设计主题的摘要,包括优缺点。每件事都是权衡的
每个部分都包含指向更深入资源的链接
根据您的面试时间表(短、中、长)建议复习的主题
问:对于面试,我需要知道这里的一切吗?
A:不,你不需要了解这里的一切来准备面试
你在面试中被问到的问题取决于以下变量:
更有经验的应聘者通常会对系统设计有更多的了解。架构师或团队领导可能会比单个贡献者了解更多。顶级科技公司可能会有一轮或多轮设计面试
从宽泛开始,在几个领域深入研究。它有助于您对各种关键的系统设计主题有所了解。根据您的时间表、经验、您面试的职位以及您面试的公司调整以下指南
Short | Medium | Long | |
---|---|---|---|
Read through the System design topics to get a broad understanding of how systems work | :+1: | :+1: | :+1: |
Read through a few articles in the Company engineering blogs for the companies you are interviewing with | :+1: | :+1: | :+1: |
Read through a few Real world architectures | :+1: | :+1: | :+1: |
Review How to approach a system design interview question | :+1: | :+1: | :+1: |
Work through System design interview questions with solutions | Some | Many | Most |
Work through Object-oriented design interview questions with solutions | Some | Many | Most |
Review Additional system design interview questions | Some | Many | Most |
如何进行撞击系统设计面试题
系统设计面试是一场开放式的谈话。希望你来领导它
您可以使用以下步骤来指导讨论。要帮助巩固此过程,请使用以下步骤完成系统设计面试问题与解决方案部分
收集需求并确定问题范围。提出问题以澄清用例和约束。讨论假设
概述包含所有重要组件的高级设计
深入了解每个核心组件的详细信息。例如,如果您被要求设计一个url缩短服务,请讨论:
在给定约束的情况下,确定并解决瓶颈问题。例如,您是否需要以下内容来解决可伸缩性问题?
讨论潜在的解决方案和权衡。每件事都是权衡的。使用可扩展系统设计原则解决瓶颈问题
你可能会被要求手工做一些估算。有关以下资源,请参阅附录:
请查看以下链接,以更好地了解预期内容:
带有示例讨论、代码和图表的常见系统设计面试问题
链接到解决方案/文件夹中内容的解决方案
Question | |
---|---|
Design Pastebin.com (or Bit.ly) | Solution |
Design the Twitter timeline and search (or Facebook feed and search) | Solution |
Design a web crawler | Solution |
Design Mint.com | Solution |
Design the data structures for a social network | Solution |
Design a key-value store for a search engine | Solution |
Design Amazon’s sales ranking by category feature | Solution |
Design a system that scales to millions of users on AWS | Solution |
Add a system design question | Contribute |
查看练习和解决方案
查看练习和解决方案
查看练习和解决方案
查看练习和解决方案
查看练习和解决方案
查看练习和解决方案
查看练习和解决方案
查看练习和解决方案
常见的面向对象设计面试问题,带有示例讨论、代码和图表
注:此部分正在开发中。
是系统设计的新手吗?
Question | |
---|---|
Design a hash map | Solution |
Design a least recently used cache | Solution |
Design a call center | Solution |
Design a deck of cards | Solution |
Design a parking lot | Solution |
Design a chat server | Solution |
Design a circular array | Contribute |
Add an object-oriented design question | Contribute |
首先,您需要基本了解通用原则,了解它们是什么、如何使用以及它们的优缺点
哈佛大学可伸缩性讲座
可扩展性
接下来,我们来看看高级权衡:
请记住,每件事都是权衡的。
然后,我们将深入探讨更具体的主题,如DNS、CDN和负载均衡器
如果服务以与添加的资源成正比的方式提高性能,则该服务是可伸缩的。通常,提高性能意味着服务更多的工作单元,但也可以处理更大的工作单元,例如当数据集增长时。1
看待性能与可伸缩性的另一种方式:
延迟是执行某种操作或产生某种结果的时间
吞吐量是每单位时间内此类操作或结果的数量
通常,您应该以具有可接受延迟的最大吞吐量为目标
资料来源:复习上限定理
在分布式计算机系统中,您只能支持以下两项保证:
网络不可靠,因此您需要支持分区容错。您需要在一致性和可用性之间进行软件权衡
等待来自分区节点的响应可能会导致超时错误。如果您的业务需求需要原子读写,CP是一个很好的选择
响应返回任何节点上可用的最容易获得的数据版本,该版本可能不是最新版本。在解析分区时,写入可能需要一些时间才能传播
如果业务需要考虑到最终的一致性,或者当系统需要在出现外部错误的情况下继续工作时,AP是一个很好的选择
对于同一数据的多个副本,我们面临着如何对它们进行同步操作的选择,以便客户对数据有一致的看法。回想一下CAP定理中的一致性定义-每次读取都会收到最近的写入或错误
写入后,读取可能会也可能看不到它。采取了尽力而为的方法
这种方法可以在memcached等系统中看到。弱一致性适用于VoIP、视频聊天和实时多人游戏等实时用例。例如,如果您正在打电话,并且在几秒钟内失去接收,那么当您重新连接时,您听不到在连接中断期间所说的话
写入之后,读取最终会看到它(通常在毫秒内)。异步复制数据
在DNS和电子邮件等系统中可以看到这种方法。最终一致性在高可用性系统中运行良好
写入后,Reads将看到它。同步复制数据
这种方法可以在文件系统和RDBMS中看到。强一致性在需要事务的系统中运行良好
支持高可用性有两种互补模式:故障切换和复制
使用主动-被动故障转移时,会在处于备用状态的主动服务器和被动服务器之间发送心跳。如果心跳中断,被动服务器将接管主动服务器的IP地址并恢复服务
停机时间的长短取决于被动服务器是否已经在“热”待机状态下运行,或者它是否需要从“冷”待机状态启动。只有活动服务器才能处理流量
主动-被动故障切换也可以称为主-从故障切换
在主动-主动模式下,两台服务器都在管理流量,在它们之间分担负载
如果服务器是面向公众的,则DNS需要知道两个服务器的公共IP。如果服务器是面向内部的,则应用程序逻辑需要了解这两个服务器
主动-主动故障切换也可以称为主-主故障切换
此主题将在数据库部分进一步讨论:
可用性通常通过正常运行时间(或停机时间)作为服务可用时间的百分比来量化。可用性通常用数字9来衡量–99.99%可用性的服务被描述为有四个9
如果服务由多个容易发生故障的组件组成,则服务的总体可用性取决于这些组件是顺序的还是并行的
Duration | Acceptable downtime |
---|---|
Downtime per year | 8h 45min 57s |
Downtime per month | 43m 49.7s |
Downtime per week | 10m 4.8s |
Downtime per day | 1m 26.4s |
Duration | Acceptable downtime |
---|---|
Downtime per year | 52min 35.7s |
Downtime per month | 4m 23s |
Downtime per week | 1m 5s |
Downtime per day | 8.6s |
当两个可用性<100%的组件按顺序排列时,总体可用性会降低:
如果Foo和Bar都有99.9%的可用性,那么它们的总可用性依次为99.8%
Availability (Total) = Availability (Foo) * Availability (Bar)
当两个可用性<100%的组件并行时,总体可用性会提高:
如果Foo和BAR都有99.9%的可用性,那么它们并行的总可用性将是99.9999%
Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar))
来源:DNS安全演示
域名系统(DNS)将域名(如www.example.com)转换为IP地址
DNS是分层的,顶层有几个权威服务器。您的路由器或ISP提供有关执行查找时联系哪些DNS服务器的信息。较低级别的DNS服务器缓存映射,这些映射可能会因DNS传播延迟而变得陈旧。您的浏览器或操作系统还可以将DNS结果缓存一段时间,具体取决于生存时间(TTL)
CloudFlare和Route 53等服务提供托管DNS服务。某些DNS服务可以通过各种方法路由流量:
CNAME
(example.com to www.example.com) or to an A
record.来源:为什么使用CDN
内容递送网络(CDN)是全球分布的代理服务器网络,提供来自更靠近用户的位置的内容。一般情况下,静电文件(如html/css/js)、照片和视频都是由云服务提供的,但有些云服务(如亚马逊的云前端)支持动态内容。站点的DNS解析将告诉客户端要联系哪个服务器
从CDN提供内容可以通过两种方式显著提高性能:
每当您的服务器发生更改时,推送CDN都会接收新内容。您负责提供内容、直接上传到CDN、重写指向CDN的URL。您可以配置内容何时过期以及何时更新。只有在内容是新的或更改的情况下才会上载内容,从而最大限度地减少流量,但最大限度地提高存储
流量较小的站点或内容不经常更新的站点可以很好地使用推送CDN。内容只放在CDN上一次,而不是定期重新拉取
拉取CDN在第一个用户请求内容时从您的服务器抓取新内容。您将内容保留在服务器上,并重写URL以指向CDN。这会导致请求速度变慢,直到内容缓存在CDN上
生存时间(TTL)确定缓存内容的时间长度。拉取CDN最大限度地减少了CDN上的存储空间,但如果文件过期并在实际更改之前被拉取,则可能会产生冗余流量
流量大的站点可以很好地使用拉式CDN,因为流量分布更均匀,只有最近请求的内容保留在CDN上
来源:可伸缩系统设计模式
负载平衡器将传入的客户端请求分发到应用程序服务器和数据库等计算资源。在每种情况下,负载均衡器都会将来自计算资源的响应返回到相应的客户端。负载均衡器在以下方面有效:
负载均衡器可以通过硬件(昂贵)或软件(如HAProxy)实现
其他优势包括:
为了防止故障,通常在主动-被动或主动-主动模式下设置多个负载均衡器
负载均衡器可以根据各种指标路由流量,包括:
第4层负载均衡器查看传输层的信息,以决定如何分发请求。通常,这涉及报头中的源IP地址、目的IP地址和端口,但不涉及数据包的内容。第4层负载均衡器转发进出上游服务器的网络数据包,执行网络地址转换(NAT)
第7层负载均衡器查看应用层以决定如何分发请求。这可能涉及标头、消息和Cookie的内容。第7层负载均衡器终止网络流量,读取消息,做出负载平衡决策,然后打开到所选服务器的连接。例如,第7层负载均衡器可以将视频流量定向到托管视频的服务器,同时将更敏感的用户计费流量定向到经过安全强化的服务器
以灵活性为代价,与第7层相比,第4层负载平衡需要更少的时间和计算资源,尽管对现代商用硬件的性能影响可能微乎其微
负载均衡器还可以帮助进行水平扩展,从而提高性能和可用性。与在更昂贵的硬件上纵向扩展单个服务器(称为垂直扩展)相比,使用商用计算机进行横向扩展更具成本效益,并带来更高的可用性。与专门的企业系统相比,在商用硬件上工作的人才也更容易招聘
来源:维基百科
反向代理是集中内部服务并向公众提供统一接口的Web服务器。在反向代理将服务器的响应返回给客户端之前,将来自客户端的请求转发到可以实现该请求的服务器
来源:规模架构系统简介
通过将Web层与应用层(也称为平台层)分开,您可以分别扩展和配置这两个层。添加新API会导致添加应用程序服务器,而不必添加额外的Web服务器。单一责任原则主张共同工作的小型自主服务。拥有小型服务的小型团队可以更积极地规划快速增长
应用程序层中的工作者也有助于启用异步
与此讨论相关的是微服务,可以将其描述为一套可独立部署的小型模块化服务。每个服务都运行一个独特的流程,并通过定义良好的轻量级机制进行通信,以服务于业务目标。1个
例如,Pinterest可以拥有以下微服务:用户档案、追随者、馈送、搜索、照片上传等
诸如Consul、etcd和ZooKeeper这样的系统可以通过跟踪注册的名称、地址和端口来帮助服务找到彼此。运行状况检查有助于验证服务完整性,通常使用HTTP端点来完成。Consul和etcd都有一个内置的键值存储,可用于存储配置值和其他共享数据
来源:向上扩展至您的第一个1000万用户
像SQL这样的关系数据库是以表形式组织的数据项的集合
ACID是关系数据库事务的一组属性
扩展关系数据库有许多技术:主-从复制、主-主复制、联合、分片、反规范化和SQL调优
主机服务于读取和写入,将写入复制到一个或多个仅服务于读取的从机。从属设备还可以以树状方式复制到其他从属设备。如果主机脱机,系统可以继续以只读模式运行,直到将从属提升为主机或调配新主机
来源:可伸缩性、可用性、稳定性、模式
两个主机都提供读写服务,并在写入时相互协调。如果任一主机发生故障,系统可以在读取和写入的情况下继续运行
来源:可伸缩性、可用性、稳定性、模式
来源:向上扩展至您的第一个1000万用户
联合(或功能分区)按功能拆分数据库。例如,您可以拥有三个数据库,而不是一个单一的整体数据库:论坛、用户和产品,从而减少每个数据库的读写流量,从而减少复制延迟。较小的数据库会产生更多可以放入内存的数据,这反过来又会因为改进的高速缓存位置而导致更多的高速缓存命中率。由于没有单个中央主机串行化写入,您可以并行写入,从而增加吞吐量
来源:可伸缩性、可用性、稳定性、模式
分片将数据分布在不同的数据库中,以便每个数据库只能管理数据的一个子集。以用户数据库为例,随着用户数量的增加,集群中会添加更多的分片
与联合的优点类似,分片可以减少读写流量、减少复制和增加缓存命中率。索引大小也会减小,这通常会通过更快的查询提高性能。如果一个碎片发生故障,其他碎片仍可运行,尽管您需要添加某种形式的复制以避免数据丢失。与联合一样,没有单个串行化写入的中央主机,允许您在提高吞吐量的同时并行写入
共享用户表的常见方式是通过用户的姓氏首字母或用户的地理位置
反规格化试图以牺牲一些写入性能为代价来提高读取性能。数据的冗余副本被写入多个表中,以避免昂贵的联接。一些RDBMS(如PostgreSQL和Oracle)支持物化视图,物化视图处理存储冗余信息和保持冗余副本一致的工作
使用联合和分片等技术分发数据后,管理跨数据中心的联接会进一步增加复杂性。反规格化可能会绕过对这种复杂连接的需要。
在大多数系统中,读取的数量可能远远超过写入的数量100:1甚至1000:1。导致复杂数据库联接的读取可能非常昂贵,会花费大量时间进行磁盘操作
SQL调优是一个涉及面很广的主题,很多书都是作为参考编写的
重要的是要进行基准测试和性能分析,以模拟和发现瓶颈
基准测试和性能分析可能会为您提供以下优化
NoSQL是键值存储、文档存储、宽列存储或图形数据库中表示的数据项的集合。数据被反规范化,连接通常在应用程序代码中完成。大多数NoSQL存储缺乏真正的ACID事务,倾向于最终的一致性
BASE通常用来描述NoSQL数据库的属性。与CAP定理相比,BASE选择可用性而不是一致性
CHAR
instead of VARCHAR
for fixed-length fields.
CHAR
effectively allows for fast, random access, whereas with VARCHAR
, you must find the end of a string before moving onto the next one.TEXT
for large blocks of text such as blog posts. TEXT
also allows for boolean searches. Using a TEXT
field results in storing a pointer on disk that is used to locate the text block.INT
for larger numbers up to 2^32 or 4 billion.DECIMAL
for currency to avoid floating point representation errors.BLOBS
, store the location of where to get the object instead.VARCHAR(255)
is the largest number of characters that can be counted in an 8 bit number, often maximizing the use of a byte in some RDBMS.NOT NULL
constraint where applicable to improve search performance.SELECT
, GROUP BY
, ORDER BY
, JOIN
) could be faster with indices.除了在SQL或NoSQL之间进行选择之外,了解哪种类型的NoSQL数据库最适合您的用例也很有帮助。在下一节中,我们将回顾键值存储、文档存储、宽列存储和图形数据库
抽象:哈希表
键值存储通常允许O(1)次读取和写入,并且通常由内存或SSD支持。数据存储可以按字典顺序维护键,从而允许高效地检索键范围。键值存储可允许存储具有值的元数据
键值存储提供高性能,通常用于简单数据模型或快速变化的数据,如内存缓存层。由于它们只提供有限的操作集,因此如果需要额外的操作,复杂性将转移到应用层
键值存储是更复杂系统(如文档存储,在某些情况下还包括图形数据库)的基础
抽象:键值存储,文档存储为值
文档存储以文档(XML、JSON、二进制等)为中心,文档存储给定对象的所有信息。文档存储提供基于文档本身的内部结构进行查询的API或查询语言。请注意,许多键值存储包括用于使用值的元数据的功能,从而模糊了这两种存储类型之间的界限
根据底层实现,文档按集合、标签、元数据或目录进行组织。尽管可以将文档组织或分组在一起,但文档的字段可能彼此完全不同
一些文档存储,如MongoDB和CouchDB,也提供了一种类似SQL的语言来执行复杂的查询。DynamoDB同时支持键值和文档
文档存储具有很高的灵活性,通常用于处理偶尔更改的数据
来源:SQL&NoSQL,简史
抽象:嵌套映射ColumnFamily<RowKey,Columns<ColKey,Value,Timestamp>>
宽列存储的基本数据单位是列(名称/值对)。列可以按列族分组(类似于SQL表)。超级柱族进一步将柱族分组。您可以使用行键单独访问每列,具有相同行键的列形成一行。每个值都包含一个用于版本化和冲突解决的时间戳
Google引入了Bigtable作为第一个宽列存储,它影响了Hadoop生态系统中经常使用的开源HBase,以及Facebook的Cassandra。Bigtable、HBase和Cassandra等存储按字典顺序维护键,从而允许高效地检索选择性键范围
宽列存储提供高可用性和高可伸缩性。它们通常用于非常大的数据集
来源:图表数据库
抽象:图表
在图形数据库中,每个节点是一条记录,每条弧是两个节点之间的关系。对图形数据库进行了优化,以表示具有多个外键或多对多关系的复杂关系
图形数据库为具有复杂关系的数据模型(如社交网络)提供高性能。它们相对较新,尚未广泛使用;可能更难找到开发工具和资源。很多图表只能通过睡觉API访问
来源:从RDBMS过渡到NoSQL
SQL的原因:
使用NoSQL的原因:
非常适合NoSQL的示例数据:
来源:可伸缩系统设计模式
缓存可以缩短页面加载时间,并可以减少服务器和数据库的负载。在此模型中,调度程序将首先查找以前是否已发出请求,并尝试查找要返回的前一个结果,以便保存实际执行
数据库通常受益于跨其分区的读和写的统一分布。受欢迎的项目可能会扭曲分布,造成瓶颈。将缓存放在数据库前面有助于吸收不均匀的负载和流量高峰
缓存可以位于客户端(操作系统或浏览器)、服务器端或位于不同的缓存层中
CDN被认为是一种缓存
反向代理和缓存(如varish)可以直接服务于静电和动态内容。Web服务器还可以缓存请求,无需联系应用程序服务器即可返回响应
您的数据库通常在默认配置中包含某种级别的缓存,针对一般用例进行了优化。针对特定的使用模式调整这些设置可以进一步提高性能
内存缓存(如memcached和redis)是应用程序和数据存储之间的键值存储。由于数据保存在RAM中,因此它比数据存储在磁盘上的典型数据库快得多。RAM比磁盘更有限,因此缓存失效算法(如最近最少使用(LRU))可以帮助使“冷”条目无效,并将“热”数据保留在RAM中
Redis具有以下附加功能:
您可以缓存多个级别,分为两个一般类别:数据库查询和对象:
通常,您应该尽量避免基于文件的缓存,因为这会增加克隆和自动缩放的难度
无论何时查询数据库,都要将查询作为键进行散列,并将结果存储到缓存中。此方法存在过期问题:
将数据视为对象,类似于您对应用程序代码所做的操作。让您的应用程序将数据库中的数据集组装成一个类实例或一个或多个数据结构:
缓存内容的建议:
由于您只能在缓存中存储有限数量的数据,因此您需要确定哪种缓存更新策略最适合您的用例
来源:从缓存到内存中数据网格
应用程序负责从存储中读取和写入。缓存不直接与存储交互。应用程序执行以下操作:
memcached通常以这种方式使用
后续读取添加到高速缓存的数据速度很快。侧缓存也称为惰性加载。仅缓存请求的数据,从而避免使用未请求的数据填满缓存
def get_user(self, user_id):
user = cache.get("user.{0}", user_id)
if user is None:
user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id)
if user is not None:
key = "user.{0}".format(user_id)
cache.set(key, json.dumps(user))
return user
来源:可伸缩性、可用性、稳定性、模式
应用程序使用高速缓存作为主数据存储,对其进行读写数据,而高速缓存负责对数据库进行读写:
应用程序代码:
缓存代码:
由于写入操作,直写操作的总体速度较慢,但后续读取刚写入的数据会很快。用户在更新数据时通常比读取数据时更能容忍延迟。缓存中的数据未过时
set_user(12345, {"foo":"bar"})
来源:可伸缩性、可用性、稳定性、模式
def set_user(user_id, values):
user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
cache.set(user_id, user)
在Write-Back中,应用程序执行以下操作:
来源:从缓存到内存中数据网格
您可以将缓存配置为在任何最近访问的缓存条目到期之前自动刷新
如果缓存可以准确预测将来可能需要哪些项目,则与直读相比,提前刷新可以降低延迟
来源:规模架构系统简介
异步工作流有助于减少代价高昂的操作的请求时间,否则这些操作将以内联方式执行。他们还可以通过提前执行耗时的工作来提供帮助,例如定期聚合数据
消息队列接收、保存和传递消息。如果操作速度太慢而无法以内联方式执行,则可以将消息队列与以下工作流结合使用:
用户不会被阻止,作业将在后台处理。在此期间,客户端可能会选择性地进行少量处理,使其看起来好像任务已经完成。例如,如果发布一条tweet,该tweet可以立即发布到您的时间表上,但可能需要一段时间才能真正将您的tweet发送给您的所有追随者
Redis作为简单的消息代理很有用,但消息可能会丢失
RabbitMQ很流行,但需要您适应‘AMQP’协议并管理您自己的节点
Amazon SQS是托管的,但可能会有很高的延迟,并且可能会传递两次消息
任务队列接收任务及其相关数据,运行它们,然后交付结果。它们可以支持调度,并可用于在后台运行计算密集型作业
芹菜支持调度,并且主要支持python。
如果队列开始显著增长,队列大小可能会大于内存,从而导致缓存未命中、磁盘读取,甚至会降低性能。反压可以通过限制队列大小来提供帮助,从而为队列中已有的作业保持较高的吞吐率和良好的响应时间。一旦队列填满,客户端就会收到服务器繁忙或HTTP 503状态代码,以便稍后重试。客户端可以稍后重试请求,可能会使用指数回退
来源:OSI 7层模型
HTTP是一种在客户端和服务器之间编码和传输数据的方法。它是一种请求/响应协议:客户端发出请求,服务器发出响应,其中包含请求的相关内容和完成状态信息。HTTP是独立的,允许请求和响应流经许多执行负载平衡、缓存、加密和压缩的中间路由器和服务器
基本HTTP请求由谓词(方法)和资源(端点)组成。以下是常见的HTTP谓词:
*可以多次调用,没有不同的结果
HTTP是依赖于较低级别协议(如TCP和UDP)的应用层协议
Verb | Description | Idempotent* | Safe | Cacheable |
---|---|---|---|---|
GET | Reads a resource | Yes | Yes | Yes |
POST | Creates a resource or trigger a process that handles data | No | No | Yes if response contains freshness info |
PUT | Creates or replace a resource | Yes | No | No |
PATCH | Partially updates a resource | No | No | Yes if response contains freshness info |
DELETE | Deletes a resource | Yes | No | No |
来源:如何制作多人游戏
TCP是IP网络上的面向连接的协议。使用握手建立和终止连接。所有发送的数据包都保证按原始顺序到达目的地,并且通过以下方式不会损坏:
如果发送方没有收到正确的响应,它将重新发送数据包。如果存在多个超时,则连接将断开。TCP还实施流量控制和拥塞控制。这些保证会导致延迟,并且通常会导致传输效率低于UDP
为了确保高吞吐量,Web服务器可以保持大量TCP连接处于打开状态,从而导致高内存使用率。在web服务器线程和memcached服务器(比方说)之间具有大量打开的连接可能代价高昂。除了在适用的情况下切换到UDP之外,连接池还可以提供帮助
TCP对于要求高可靠性但对时间要求较低的应用程序很有用。一些示例包括Web服务器、数据库信息、SMTP、FTP和SSH
在以下情况下使用UDP上的TCP:
来源:如何制作多人游戏
UDP是无连接的。数据报(类似于数据包)仅在数据报级别得到保证。数据报可能无序到达目的地,也可能根本没有到达目的地。UDP不支持拥塞控制。如果没有TCP支持的保证,UDP通常更有效
UDP可以广播,向子网中的所有设备发送数据报。这对于DHCP很有用,因为客户端尚未接收到IP地址,因此阻止了TCP在没有IP地址的情况下流式传输
UDP的可靠性较低,但在VoIP、视频聊天、流和实时多人游戏等实时使用案例中运行良好
在以下情况下使用TCP上的UDP:
来源:破解系统设计访谈
在RPC中,客户端导致过程在不同的地址空间(通常是远程服务器)上执行。该过程的编码就好像它是一个本地过程调用,从客户端程序抽象出如何与服务器通信的细节。远程调用通常比本地调用更慢、更不可靠,因此区分RPC调用和本地调用很有帮助。流行的RPC框架包括Protobuf、Thrift和Avro
RPC是一种请求-响应协议:
示例RPC调用:
RPC专注于公开行为。RPC通常用于内部通信的性能原因,因为您可以手工创建本地调用以更好地适应您的用例
在以下情况下选择本机库(也称为SDK):
GET /someoperation?data=anId
POST /anotheroperation
{
"data":"anId";
"anotherdata": "another value"
}
睡觉之后的HTTP接口倾向于更常用于公共接口
睡觉是一种实施客户端/服务器模型的体系结构风格,其中客户端作用于由服务器管理的一组资源。服务器提供资源和动作的表示,这些资源和动作既可以操作资源,也可以获得新的资源表示。所有通信必须是无状态和可缓存的
REST风格的界面有四个特点:
睡觉调用示例:
睡觉专注于数据曝光。它最大限度地减少了客户端/服务器之间的耦合,通常用于公共HTTPAPI。睡觉使用一种更通用、更统一的方法,通过URI公开资源,通过头部表示,通过GET、POST、PUT、DELETE和PATCH等动词进行操作。由于是无状态的,睡觉非常适合水平伸缩和分区
来源:你真的知道为什么你更喜欢睡觉而不是rpc吗?
GET /someresources/anId
PUT /someresources/anId
{"anotherdata": "another value"}
此部分可能需要一些更新。考虑捐款吧!
Operation | RPC | REST |
---|---|---|
Signup | POST /signup | POST /persons |
Resign | POST /resign { “personid”: “1234” } |
DELETE /persons/1234 |
Read a person | GET /readPerson?personid=1234 | GET /persons/1234 |
Read a person’s items list | GET /readUsersItemsList?personid=1234 | GET /persons/1234/items |
Add an item to a person’s items | POST /addItemToUsersItemsList { “personid”: “1234”; “itemid”: “456” } |
POST /persons/1234/items { “itemid”: “456” } |
Update an item | POST /modifyItem { “itemid”: “456”; “key”: “value” } |
PUT /items/456 { “key”: “value” } |
Delete an item | POST /removeItem { “itemid”: “456” } |
DELETE /items/456 |
安全是一个广泛的话题。除非你有相当多的经验,有安全背景,或者正在申请一个需要安全知识的职位,否则你可能不需要知道更多的基础知识:
有时你会被要求做“粗略”的估算。例如,您可能需要确定从磁盘生成100个图像缩略图需要多长时间,或者一个数据结构需要多少内存。每个程序员都应该知道的两个表的幂和延迟数字是很方便的参考资料
基于以上数字的便捷指标:
Power Exact Value Approx Value Bytes
---------------------------------------------------------------
7 128
8 256
10 1024 1 thousand 1 KB
16 65,536 64 KB
20 1,048,576 1 million 1 MB
30 1,073,741,824 1 billion 1 GB
32 4,294,967,296 4 GB
40 1,099,511,627,776 1 trillion 1 TB
Latency Comparison Numbers
--------------------------
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns 14x L1 cache
Mutex lock/unlock 25 ns
Main memory reference 100 ns 20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy 10,000 ns 10 us
Send 1 KB bytes over 1 Gbps network 10,000 ns 10 us
Read 4 KB randomly from SSD* 150,000 ns 150 us ~1GB/sec SSD
Read 1 MB sequentially from memory 250,000 ns 250 us
Round trip within same datacenter 500,000 ns 500 us
Read 1 MB sequentially from SSD* 1,000,000 ns 1,000 us 1 ms ~1GB/sec SSD, 4X memory
HDD seek 10,000,000 ns 10,000 us 10 ms 20x datacenter roundtrip
Read 1 MB sequentially from 1 Gbps 10,000,000 ns 10,000 us 10 ms 40x memory, 10X SSD
Read 1 MB sequentially from HDD 30,000,000 ns 30,000 us 30 ms 120x memory, 30X SSD
Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms
Notes
-----
1 ns = 10^-9 seconds
1 us = 10^-6 seconds = 1,000 ns
1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns
常见的系统设计面试问题,以及有关如何解决每个问题的资源链接
有关如何设计真实系统的文章
来源:Twitter时间表按规模
Question | Reference(s) |
---|---|
Design a file sync service like Dropbox | youtube.com |
Design a search engine like Google | queue.acm.org stackexchange.com ardendertat.com stanford.edu |
Design a scalable web crawler like Google | quora.com |
Design Google docs | code.google.com neil.fraser.name |
Design a key-value store like Redis | slideshare.net |
Design a cache system like Memcached | slideshare.net |
Design a recommendation system like Amazon’s | hulu.com ijcai13.org |
Design a tinyurl system like Bitly | n00tc0d3r.blogspot.com |
Design a chat app like WhatsApp | highscalability.com |
Design a picture sharing system like Instagram | highscalability.com highscalability.com |
Design the Facebook news feed function | quora.com quora.com slideshare.net |
Design the Facebook timeline function | facebook.com highscalability.com |
Design the Facebook chat function | erlang-factory.com facebook.com |
Design a graph search function like Facebook’s | facebook.com facebook.com facebook.com |
Design a content delivery network like CloudFlare | figshare.com |
Design a trending topic system like Twitter’s | michael-noll.com snikolov .wordpress.com |
Design a random ID generation system | blog.twitter.com github.com |
Return the top k requests during a time interval | cs.ucsb.edu wpi.edu |
Design a system that serves data from multiple data centers | highscalability.com |
Design an online multiplayer card game | indieflashblog.com buildnewgames.com |
Design a garbage collection system | stuffwithstuff.com washington.edu |
Design an API rate limiter | https://stripe.com/blog/ |
Design a Stock Exchange (like NASDAQ or Binance) | Jane Street Golang Implementation Go Implemenation |
Add a system design question | Contribute |
在下面的文章中,不要把重点放在具体的细节上,而是:
您面试的公司的架构
您遇到的问题可能来自同一个域
Type | System | Reference(s) |
---|---|---|
Data processing | MapReduce – Distributed data processing from Google | research.google.com |
Data processing | Spark – Distributed data processing from Databricks | slideshare.net |
Data processing | Storm – Distributed data processing from Twitter | slideshare.net |
Data store | Bigtable – Distributed column-oriented database from Google | harvard.edu |
Data store | HBase – Open source implementation of Bigtable | slideshare.net |
Data store | Cassandra – Distributed column-oriented database from Facebook | slideshare.net |
Data store | DynamoDB – Document-oriented database from Amazon | harvard.edu |
Data store | MongoDB – Document-oriented database | slideshare.net |
Data store | Spanner – Globally-distributed database from Google | research.google.com |
Data store | Memcached – Distributed memory caching system | slideshare.net |
Data store | Redis – Distributed memory caching system with persistence and value types | slideshare.net |
File system | Google File System (GFS) – Distributed file system | research.google.com |
File system | Hadoop File System (HDFS) – Open source implementation of GFS | apache.org |
Misc | Chubby – Lock service for loosely-coupled distributed systems from Google | research.google.com |
Misc | Dapper – Distributed systems tracing infrastructure | research.google.com |
Misc | Kafka – Pub/sub message queue from LinkedIn | slideshare.net |
Misc | Zookeeper – Centralized infrastructure and services enabling synchronization | slideshare.net |
Add an architecture | Contribute |
想要添加博客吗?为避免重复工作,请考虑将您的公司博客添加到以下回购中:
有兴趣添加一个部分或帮助完成一个正在进行的部分吗?贡献自己的力量!
在整个回购过程中提供积分和来源
特别感谢:
请随时与我联系,讨论任何问题、问题或评论
我的联系信息可以在我的GitHub页面上找到
我在开放源码许可下向您提供此存储库中的代码和资源。因为这是我的个人存储库,您获得的我的代码和资源的许可证来自我,而不是我的雇主(Facebook)
动机
Anki抽认卡
Copyright 2017 Donne Martin
Creative Commons Attribution 4.0 International License (CC BY 4.0)
http://creativecommons.org/licenses/by/4.0/
Documentation |
---|
TensorFlow是一个端到端的机器学习开源平台。它有一个由工具、库和社区资源组成的全面、灵活的生态系统,使研究人员能够使用ML推动最先进的技术,开发人员可以轻松地构建和部署基于ML的应用程序
TensorFlow最初是由谷歌机器智能研究组织内谷歌大脑团队的研究人员和工程师开发的,目的是进行机器学习和深度神经网络研究。该系统具有足够的通用性,可以广泛应用于其他领域
TensorFlow提供稳定的Python和C++API,以及不保证向后兼容的其他语言API
订阅untify@tensorflow.org,随时了解最新的版本公告和安全更新。查看所有邮件列表
请参阅PIP包的TensorFlow安装指南,要启用GPU支持,请使用Docker容器,并从源代码构建
要安装当前版本(包括对启用CUDA的GPU卡(Ubuntu和Windows)的支持),请执行以下操作:
$ pip install tensorflow
此外,还提供了一个较小的仅限CPU的软件包:
$ pip install tensorflow-cpu
要将TensorFlow更新到最新版本,请在上述命令中添加–upgrade标志
夜间二进制文件可用于在PyPI上使用tf-nighly和tf-nighly-cpu包进行测试
$ python
>>> import tensorflow as tf
>>> tf.add(1, 2).numpy()
3
>>> hello = tf.constant('Hello, TensorFlow!')
>>> hello.numpy()
b'Hello, TensorFlow!'
有关更多示例,请参阅TensorFlow教程
如果您想对TensorFlow做出贡献,请务必查看贡献指南。该项目遵循TensorFlow的行为准则。通过参与,您应该遵守本守则
我们使用GitHub问题来跟踪请求和错误,有关一般问题和讨论,请参阅TensorFlow讨论,并请将具体问题直接指向Stack Overflow
TensorFlow项目致力于遵守开源软件开发中公认的最佳实践:
您可以在TensorFlow SIG build社区构建表中找到更多社区支持的平台和配置
Build Type | Status | Artifacts |
---|---|---|
Linux CPU | PyPI | |
Linux GPU | PyPI | |
Linux XLA | TBA | |
macOS | PyPI | |
Windows CPU | PyPI | |
Windows GPU | PyPI | |
Android | ||
Raspberry Pi 0 and 1 | Py3 | |
Raspberry Pi 2 and 3 | Py3 | |
Libtensorflow MacOS CPU | Status Temporarily Unavailable | Nightly Binary Official GCS |
Libtensorflow Linux CPU | Status Temporarily Unavailable | Nightly Binary Official GCS |
Libtensorflow Linux GPU | Status Temporarily Unavailable | Nightly Binary Official GCS |
Libtensorflow Windows CPU | Status Temporarily Unavailable | Nightly Binary Official GCS |
Libtensorflow Windows GPU | Status Temporarily Unavailable | Nightly Binary Official GCS |
了解有关TensorFlow社区以及如何做出贡献的更多信息
Apache License 2.0
该存储库包含完整的Python数据科学手册,其形式为(免费!)Jupyter笔记本
本书是使用Python3.5编写和测试的,尽管其他Python版本(包括Python2.7)几乎可以在所有情况下运行
本书介绍了在Python中使用数据所必需的核心库:特别是IPython、NumPy、Pandas、Matplotlib、Scikit-Learning和相关包。假设您熟悉Python作为一种语言;如果您需要快速介绍该语言本身,请参阅免费的配套项目-Python旋风之旅:这是针对研究人员和科学家的快速Python语言介绍
请参见Index.ipynb以获取可与文本一起使用的笔记本的索引
书中的代码使用Python 3.5进行了测试,但大多数(但不是全部)也可以在Python 2.7和其他较早的Python版本中正常运行
我用来运行这本书中的代码的包列在Requirements.txt中(请注意,其中一些确切的版本号在您的平台上可能不可用:您可能必须调整它们以供您自己使用)。要使用CONDA安装需求,请在命令行运行以下命令:
$ conda install --file requirements.txt
要使用Python 3.5和所有必需的软件包版本创建名为pdsh的独立环境,请运行以下命令:
$ conda create -n PDSH python=3.5 --file requirements.txt
您可以在Conda文档的管理环境一节中阅读有关使用Conda环境的更多信息
此存储库中的代码,包括上面列出的笔记本中的所有代码示例,都是在MIT许可下发布的。阅读更多关于开放源码计划的内容
本书的文本内容在CC-by-NC-ND许可下发布。在知识共享网站上阅读更多内容
这是Python改变生活
系列的第三篇,讲到了如何通过Python的pyzbar批量识别快递单号的条形码,以提高我们的生活工作效率,这是一篇实战教程。
了解我的小伙伴可能都知道,小五经常给大家送书。最近一年,不算联合抽奖送书,单独我自购+出版社赞助已送出1000本书籍。
如果是自购的话,还需要自己联系快递小哥寄出书籍。
寄出后快递小哥会给我截图来反馈,然而我想要单号的时候就遇到问题了。
每次寄完书,我都只能得到n个截图(内含快递信息)。
为了及时反馈大家物流信息,我需要尽快将快递单号提取出来。
每次大概都有十几到几十张截图,手动去识别真的太麻烦。
不如先看看每张截图大概是什么样子,再去想想批量处理的办法吧。
主要是为了批量获取图片中的快递单号,我想到了两个解决办法:
用python识别条形码来直接获得准确快递单号
用python调用ocr,识别截图中的快递单号文字
大家觉得哪个更简单更准确呢?
今天我先聊聊第一种方法的流程和踩坑经历。
首先,第一步需要先获取文件夹中的所有截图,再依次进行条形码识别。
具体操作可以参考注释
import os
def get_jpg():
jpgs = []
path = os.getcwd()
for i in os.listdir(path): #获取文件列表
if i.split(".")[-1] == "jpg": #筛选jpg文件(截图)
oldname=os.path.join(path,i) #旧文件名
i = i.replace('微信图片_','')
newname=os.path.join(path,i) #新文件名
os.rename(oldname,newname) #改名
jpgs.append(i)
return jpgs
上面的代码中除了遍历筛选图片,还涉及了改名的操作。
这是因为我在后面使用 opencv 时,打开的路径只要含有中文就会一直报错,于是我就干脆把截图名称里的中文去除。
执行构建的get_jpg()
函数,得到
这些就是演示文件中的四个截图文件,下面开始对他们进行识别。
python的第三方模块 pyzbar
可以很方便地处理二维码的识别。我们这次用它来识别一维条形码的话,用法也大致一样。不过还要搭配 cv2 使用,主要是为了利用cv2.imread()
来读取图片文件。
注意:对于cv2模块,安装时需要输入
pip3 install opencv-python
,但在导入的时候采用import cv2
。
识别条形码的具体语句如下所示:
import pyzbar.pyzbar as pyzbar
import cv2
def get_barcode(img):
image = cv2.imread(img)
barcodes = pyzbar.decode(image)
barcode = barcodes[0]
barcode_data = barcode.data.decode("utf-8")
return barcode_data
上面构建的get_barcode()
函数可以实现识别条形码,并返回结果数据。
我们可以用for循环遍历前文获取的所有图片,再依次使用get_barcode()
函数来识别条形码。
data_m =[]
for i in jpgs:
data = get_barcode(i)
data_m.append(data)
data_m
可以发现,成功识别了四张截图里的条形码,并获取了对应的快递单号。
回顾今天的问题案例,我先通过思考想出了两种解决办法。第一种的优点是识别条形码比OCR更准确,但是其只获取了快递单号。后续在给获得赠书的同学反馈时,我还需要手动将名字和单号对应,不够偷懒。后续将给大家介绍第二种方法的流程和优缺点。
如果想看更多python改变生活的真实问题案例,给本文右下角点个赞吧👍
如果你也有一直想用python解决的问题,欢迎在评论区告诉我🚀
本文转自快学Python。
我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应红字验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
点击下方阅读原文可获得更好的阅读体验
Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典
如果你想周期性地执行某个Python函数或脚本,最出名的选择应该是Crontab,但是Crontab具有以下缺点:
还有一个选择是Celery,但是Celery的配置比较麻烦,如果你只是需要一个轻量级的调度工具,那么Celery不是一个好选择。
在你想要使用一个轻量级的任务调度工具,而且希望它尽量简单、容易使用、不需要外部依赖,最好能够容纳Crontab的所有基本功能,那么Schedule模块是你的不二之选。
使用它来调度任务可能只需要几行代码,感受一下:
# Python 实用宝典 import schedule import time def job(): print("I'm working...") schedule.every(10).minutes.do(job) while True: schedule.run_pending() time.sleep(1)
上面的代码表示每10分钟执行一次job函数,非常简单方便。你只需要引入schedule模块,通过调用 `scedule.every(时间数).时间类型.do(job)` 发布周期任务。
发布后的周期任务需要用 run_pending 函数来检测是否执行,因此需要一个While循环不断地轮询这个函数。
下面具体讲讲Schedule模块的安装和初级、进阶使用方法。
开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。
(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.
(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南
Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:
pip install schedule
最基本的使用在文首已经提到过,下面给大家展示更多的调度任务例子:
# Python 实用宝典 import schedule import time def job(): print("I'm working...") # 每十分钟执行任务 schedule.every(10).minutes.do(job) # 每个小时执行任务 schedule.every().hour.do(job) # 每天的10:30执行任务 schedule.every().day.at("10:30").do(job) # 每个月执行任务 schedule.every().monday.do(job) # 每个星期三的13:15分执行任务 schedule.every().wednesday.at("13:15").do(job) # 每分钟的第17秒执行任务 schedule.every().minute.at(":17").do(job) while True: schedule.run_pending() time.sleep(1)
可以看到,从月到秒的配置,上面的例子都覆盖到了。不过如果你想只运行一次任务的话,可以这么配:
# Python 实用宝典 import schedule import time def job_that_executes_once(): # 此处编写的任务只会执行一次... return schedule.CancelJob schedule.every().day.at('22:30').do(job_that_executes_once) while True: schedule.run_pending() time.sleep(1)
参数传递
如果你有参数需要传递给作业去执行,你只需要这么做:
# Python 实用宝典 import schedule def greet(name): print('Hello', name) # do() 将额外的参数传递给job函数 schedule.every(2).seconds.do(greet, name='Alice') schedule.every(4).seconds.do(greet, name='Bob')
获取目前所有的作业
如果你想获取目前所有的作业,可以这么做:
# Python 实用宝典 import schedule def hello(): print('Hello world') schedule.every().second.do(hello) all_jobs = schedule.get_jobs()
取消所有作业
如果某些机制触发了,你需要立即清除当前程序的所有作业,需要这么使用:
# Python 实用宝典 import schedule def greet(name): print('Hello {}'.format(name)) schedule.every().second.do(greet) schedule.clear()
标签功能
在设置作业的时候,为了后续方便管理作业,你可以给作业打个标签,这样你可以通过标签过滤获取作业或取消作业。
# Python 实用宝典 import schedule def greet(name): print('Hello {}'.format(name)) # .tag 打标签 schedule.every().day.do(greet, 'Andrea').tag('daily-tasks', 'friend') schedule.every().hour.do(greet, 'John').tag('hourly-tasks', 'friend') schedule.every().hour.do(greet, 'Monica').tag('hourly-tasks', 'customer') schedule.every().day.do(greet, 'Derek').tag('daily-tasks', 'guest') # get_jobs(标签):可以获取所有该标签的任务 friends = schedule.get_jobs('friend') # 取消所有 daily-tasks 标签的任务 schedule.clear('daily-tasks')
设定作业截止时间
如果你需要让某个作业到某个时间截止,你可以通过这个方法:
# Python 实用宝典 import schedule from datetime import datetime, timedelta, time def job(): print('Boo') # 每个小时运行作业,18:30后停止 schedule.every(1).hours.until("18:30").do(job) # 每个小时运行作业,2030-01-01 18:33 today schedule.every(1).hours.until("2030-01-01 18:33").do(job) # 每个小时运行作业,8个小时后停止 schedule.every(1).hours.until(timedelta(hours=8)).do(job) # 每个小时运行作业,11:32:42后停止 schedule.every(1).hours.until(time(11, 33, 42)).do(job) # 每个小时运行作业,2020-5-17 11:36:20后停止 schedule.every(1).hours.until(datetime(2020, 5, 17, 11, 36, 20)).do(job)
截止日期之后,该作业将无法运行。
立即运行所有作业,而不管其安排如何
如果某个机制触发了,你需要立即运行所有作业,可以调用 schedule.run_all() :
# Python 实用宝典 import schedule def job_1(): print('Foo') def job_2(): print('Bar') schedule.every().monday.at("12:40").do(job_1) schedule.every().tuesday.at("16:40").do(job_2) schedule.run_all() # 立即运行所有作业,每次作业间隔10秒 schedule.run_all(delay_seconds=10)
装饰器安排作业
如果你觉得设定作业这种形式太啰嗦了,也可以使用装饰器模式:
# Python 实用宝典 from schedule import every, repeat, run_pending import time # 此装饰器效果等同于 schedule.every(10).minutes.do(job) @repeat(every(10).minutes) def job(): print("I am a scheduled job") while True: run_pending() time.sleep(1)
并行执行
默认情况下,Schedule 按顺序执行所有作业。其背后的原因是,很难找到让每个人都高兴的并行执行模型。
不过你可以通过多线程的形式来运行每个作业以解决此限制:
# Python 实用宝典 import threading import time import schedule def job1(): print("I'm running on thread %s" % threading.current_thread()) def job2(): print("I'm running on thread %s" % threading.current_thread()) def job3(): print("I'm running on thread %s" % threading.current_thread()) def run_threaded(job_func): job_thread = threading.Thread(target=job_func) job_thread.start() schedule.every(10).seconds.do(run_threaded, job1) schedule.every(10).seconds.do(run_threaded, job2) schedule.every(10).seconds.do(run_threaded, job3) while True: schedule.run_pending() time.sleep(1)
日志记录
Schedule模块同时也支持logging日志记录,这么使用:
# Python 实用宝典 import schedule import logging logging.basicConfig() schedule_logger = logging.getLogger('schedule') # 日志级别为DEBUG schedule_logger.setLevel(level=logging.DEBUG) def job(): print("Hello, Logs") schedule.every().second.do(job) schedule.run_all() schedule.clear()
效果如下:
DEBUG:schedule:Running *all* 1 jobs with 0s delay in between DEBUG:schedule:Running job Job(interval=1, unit=seconds, do=job, args=(), kwargs={}) Hello, Logs DEBUG:schedule:Deleting *all* jobs
异常处理
Schedule不会自动捕捉异常,它遇到异常会直接抛出,这会导致一个严重的问题:后续所有的作业都会被中断执行,因此我们需要捕捉到这些异常。
你可以手动捕捉,但是某些你预料不到的情况需要程序进行自动捕获,加一个装饰器就能做到了:
# Python 实用宝典 import functools def catch_exceptions(cancel_on_failure=False): def catch_exceptions_decorator(job_func): @functools.wraps(job_func) def wrapper(*args, **kwargs): try: return job_func(*args, **kwargs) except: import traceback print(traceback.format_exc()) if cancel_on_failure: return schedule.CancelJob return wrapper return catch_exceptions_decorator @catch_exceptions(cancel_on_failure=True) def bad_task(): return 1 / 0 schedule.every(5).minutes.do(bad_task)
这样,bad_task在执行时遇到的任何错误,都会被catch_exceptions捕获,这点在保证调度任务正常运转的时候非常关键。
我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典
FlashText算法是由Vikash Singh于2017年发表的大规模替换字符串算法,这个算法的时间复杂度仅由文本长度(N)决定,算法时间复杂度为O(N)。
而对于正则表达式的替换,算法时间复杂度还需要考虑被替换的关键词数量(M),因此时间复杂度为O(MxN)。
简而言之,基于FlashText算法的字符串替换比正则表达式替换快M倍以上,这个M是需要替换的关键词数量,关键词越多,FlashText算法的优势就越明显。
下面就给大家介绍如何在 Python 中基于 flashtext 模块使用 FlashText 算法进行字符串查找和替换,如果觉得对你的项目团队很有帮助,请记得帮作者转发一下哦。
开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。
(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.
(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南
Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:
pip install flashtext
提取关键词
一个最基本的提取关键词的例子如下:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. 添加关键词 keyword_processor.add_keyword('Big Apple', 'New York') keyword_processor.add_keyword('Bay Area') # 3. 处理目标句子并提取相应关键词 keywords_found = keyword_processor.extract_keywords('I love Big Apple and Bay Area.') # 4. 结果 print(keywords_found) # ['New York', 'Bay Area']
其中 add_keyword 的第一个参数代表需要被查找的关键词,第二个参数是给这个关键词一个别名,如果找到了则以别名显示。
替换关键词
如果你想要替换关键词,只需要调用处理器的 replace_keywords 函数:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. 添加关键词 keyword_processor.add_keyword('New Delhi', 'NCR region') # 3. 替换关键词 new_sentence = keyword_processor.replace_keywords('I love Big Apple and new delhi.') # 4. 结果 print(new_sentence) # 'I love New York and NCR region.'
关键词大小写敏感
如果你需要精确提取,识别大小写字母,那么你可以在处理器初始化的时候设定 sensitive 参数:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器, 注意设置大小写敏感(case_sensitive)为TRUE keyword_processor = KeywordProcessor(case_sensitive=True) # 2. 添加关键词 keyword_processor.add_keyword('Big Apple', 'New York') keyword_processor.add_keyword('Bay Area') # 3. 处理目标句子并提取相应关键词 keywords_found = keyword_processor.extract_keywords('I love big Apple and Bay Area.') # 4. 结果 print(keywords_found) # ['Bay Area']
标记关键词位置
如果你需要获取关键词在句子中的位置,在 extract_keywords 的时候添加 span_info=True 参数即可:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. 添加关键词 keyword_processor.add_keyword('Big Apple', 'New York') keyword_processor.add_keyword('Bay Area') # 3. 处理目标句子并提取相应关键词, 并标记关键词的起始、终止位置 keywords_found = keyword_processor.extract_keywords('I love big Apple and Bay Area.', span_info=True) # 4. 结果 print(keywords_found) # [('New York', 7, 16), ('Bay Area', 21, 29)]
获取目前所有的关键词
如果你需要获取当前已经添加的所有关键词,只需要调用处理器的get_all_keywords 函数:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. 添加关键词 keyword_processor.add_keyword('j2ee', 'Java') keyword_processor.add_keyword('colour', 'color') # 3. 获取所有关键词 keyword_processor.get_all_keywords() # output: {'colour': 'color', 'j2ee': 'Java'}
批量添加关键词
批量添加关键词有两种方法,一种是通过词典,一种是通过数组:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. (第一种)通过字典批量添加关键词 keyword_dict = { "java": ["java_2e", "java programing"], "product management": ["PM", "product manager"] } keyword_processor.add_keywords_from_dict(keyword_dict) # 2. (第二种)通过数组批量添加关键词 keyword_processor.add_keywords_from_list(["java", "python"]) # 3. 第一种的提取效果如下 keyword_processor.extract_keywords('I am a product manager for a java_2e platform') # output ['product management', 'java']
单一或批量删除关键词
删除关键词也非常简单,和添加类似:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. 通过字典批量添加关键词 keyword_dict = { "java": ["java_2e", "java programing"], "product management": ["PM", "product manager"] } keyword_processor.add_keywords_from_dict(keyword_dict) # 3. 提取效果如下 print(keyword_processor.extract_keywords('I am a product manager for a java_2e platform')) # ['product management', 'java'] # 4. 单个删除关键词 keyword_processor.remove_keyword('java_2e') # 5. 批量删除关键词,也是可以通过词典或者数组的形式 keyword_processor.remove_keywords_from_dict({"product management": ["PM"]}) keyword_processor.remove_keywords_from_list(["java programing"]) # 6. 删除了java programing关键词后的效果如下 keyword_processor.extract_keywords('I am a product manager for a java_2e platform') # ['product management']
支持额外信息
前面提到在添加关键词的时候第二个参数为其别名,其实你不仅可以指示别名,还可以将额外信息放到第二个参数中:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 kp = KeywordProcessor() # 2. 添加关键词并附带额外信息 kp.add_keyword('Taj Mahal', ('Monument', 'Taj Mahal')) kp.add_keyword('Delhi', ('Location', 'Delhi')) # 3. 效果如下 kp.extract_keywords('Taj Mahal is in Delhi.') # [('Monument', 'Taj Mahal'), ('Location', 'Delhi')]
这样,在提取关键词的时候,你还能拿到其他一些你想要在得到此关键词时输出的信息。
支持特殊单词边界
Flashtext 检测的单词边界一般局限于 \w [A-Za-z0-9_] 外的任意字符,但是如果你想添加某些特殊字符作为单词的一部分也是可以实现的:
from flashtext import KeywordProcessor # 1. 初始化关键字处理器 keyword_processor = KeywordProcessor() # 2. 添加关键词 keyword_processor.add_keyword('Big Apple') # 3. 正常效果 print(keyword_processor.extract_keywords('I love Big Apple/Bay Area.')) # ['Big Apple'] # 4. 将 '/' 作为单词一部分 keyword_processor.add_non_word_boundary('/') # 5. 优化后的效果 print(keyword_processor.extract_keywords('I love Big Apple/Bay Area.')) # []
个人认为这个模块已经满足我们的基本使用了,如果你有一些该模块提供的功能之外的使用需求,可以给 flashtext 贡献代码:
https://github.com/vi3k6i5/flashtext
附 FlashText 与正则相比 查询关键词 所花费的时间之比:
附 FlashText 与正则相比 替换关键词 所花费的时间之比:
这篇文章如果对你有帮助的话,记得转发一下哦。
我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典
Birdseye是一个Python调试器,它在函数调用中记录表达式的值,并让你在函数**退出**后轻松查看它们。例如:
无论你如何运行或编辑代码,都可以使用Birdseye。只需要你安装好依赖:
pip install birdseye
并在代码函数上方添加 @eye
装饰器(如上所示),即可根据需要运行函数,并在浏览器中查看结果。
它还可以与一些常用工具集成在一起,如 Pycharm 和 Vscode,以提供更流畅的体验,后续我们会介绍如何将其与这些工具结合使用。
它不仅仅能够单步执行,还能在循环迭代中来回移动,并查看所选表达式的值如何变化:
通过 birdseye 你能很容易地知道哪些表达式引发了异常:
你也能够展开具体的数据结构和对象以查看其内容:
调用会按功能组织(文件组织)并进行时间排序进行显示,让你一目了然地看到发生了什么:
首先,使用 pip 安装 birdseye :
pip install birdseye
然后,对需要进行调试的函数使用eye装饰器:
from birdseye import eye @eye def foo():
在你调用该函数完成后,在终端运行命令打开Birdseye的Web服务:
python -m birdseye
在浏览器打开 http://localhost:7777 就能看到需要调试的函数执行流程了。点击下图的按钮即可跳转到最新的函数调用。
在 Pycharm 的 Settings 中,点击 Plugins 插件市场搜索 birdseye 点击 install 安装。
安装完成后重启Pycharm,就可以在 Pycharm 中使用 birdseye了:
默认情况下,该插件还可以为你自动运行Birdseye服务器,因此就不需要输入 python -m birdseye 那行命令了。
在VSCode中继承调试Birdseye也非常方便,点击左侧的扩展商店,在弹出框中输入搜索 birdseye,并点击 install 安装:
安装完成后,点击 F1 输入Birdseye,就能显示调试界面:
如果无法正常显示右侧调试界面,并提示未安装birdseye,但实际上你已经安装成功了,这一般是路径错误导致的,请在扩展设置中手动更改python路径为你安装了Birdseye的Python。
Birdseye 是一个非常强大的调试工具,但我认为这还是有缺点可以改善的:
1.为了防止堆栈过大,每个迭代它最多只保留6个(前三、末三)元素:
因此如果你想看一些特殊元素值的执行情况,它可能不会如你所愿。
不过,不需要担心某些分支你调试不到,因为 birdseye 有个保险机制:如果一个表达式仅在某种特定情况下会被执行,那么执行时的元素也会被加入到可调试元素中。
2.由于需要记录堆栈,程序会大大减慢速度,因此它绝对不适合上到生产环境。
3.每个函数调用,Birdseye 都需要收集许多数据,对于某些极其复杂的函数调用,可能会引发内存问题。
如果你不担心这三个缺点,而且希望能快速方便地看到函数中不同分支的执行情况,那么Birdseye就是你的不二之选。
我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典
今天给大家介绍一个懒人 Python 库:Pyforest,只用一行代码,就能导入所有的 Python 库(本地已经安装的)。
项目地址:https://github.com/8080labs/pyforest
/ 01 / 介绍
Python 因为有着成千上万个功能强大的开源库,备受大家的欢迎
目前,通过 PyPl 可以导入超过 23.5 万个 Python 库,数量庞大
在大家平常的实践当中,一般都是需要导入多个库或者框架来执行任务
而且每当新建一个程序文件时,都需要根据自己的需求导入相关的库
如果是相同类型的任务,比如想做一个数据可视化的小项目,可能会一直使用到某个库
如此,反复编写同一条 import 语句,就算是复制粘贴,也会感觉到麻烦,这时 Pyforest 库就可以上场了
Pyforest 是一个开源的 Python 库,可以自动导入代码中使用到的 Python 库
在进行数据可视化的时候,一般都需要导入多个库,比如 pandas、numpy、matplotlib 等等
使用了 Pyforest,每个程序文件中就不需要导入相同的 Python 库,而且也不必使用确切的导入语句
比如下面这行代码,就可以省略掉
from sklearn.ensemble import RandomForestClassifier
在你使用 import 语句导入Pyforest 库后,你就可以直接使用所有的 Python 库
import pyforest
df = pd.read_csv(‘test.csv’)
print(df)
你使用的任何库都不需要使用 import 语句导入,Pyforest 会为你自动导入。
只有在代码中调用库或创建库的对象后,才会导入库。如果一个库没有被使用或调用,Pyforest 将不会导入它。
/ 02 / 使用
安装,使用以下命令安装 Pyforest
pip install pyforest -i https://pypi.tuna.tsinghua.edu.cn/simple
安装成功后,使用 import 语句导入它
现在,你可以直接使用相关的 Python 库,无需编写 import 导入
先以 jupiter notebook 为例,我们没有导入 pandas、seaborn 和 matplotlib 库,但是我们可以通过导入 Pyforest 库直接使用它们
读取数据,这个是国内棉花产量排行前三的省份,新疆全国第一(数据来源:国家统计局)
那么 Pyforest 可以导入所有库吗?
目前这个包包含了大部分流行的 Python 库,比如
pandas as pd
NumPy as np
matplotlob.pyplot as plt
seaborn as sns
除了这些库之外,它还提供了一些辅助的 Python 库,如 os、tqdm、re 等
如果你想查看库列表,可以使用 dir(pyforest) 进行查看,内置的是 68 个库
import pyforest
print(len(dir(pyforest)))
for i in dir(pyforest):
print(i)
————————-
68
GradientBoostingClassifier
GradientBoostingRegressor
LazyImport
OneHotEncoder
Path
RandomForestClassifier
RandomForestRegressor
SparkContext
TSNE
TfidfVectorizer
…
如果没有的话,可以进行自定义添加,在主目录中的文件写入 import 语句
示例如下
vim ~/.pyforest/user_imports.py
添加语句,此处便能在代码中使用 requests 这个库
# Add your imports here, line by line
# e.g
# import pandas as pd
# from pathlib import Path
# import re
import requests as req
~
~
“~/.pyforest/user_imports.py” 7L, 129C
这回我们在 PyCharm 中来实验一下。
发现 PyCharm 的自动补全的功能失效了,看来这个库还是比较适合 jupyter notebook(自动补全代码还可以使用)
除了上面这个地方可以自定义添加,还可以在库的 _import.py 文件中添加
此处以 Pyechars 为例,缩写为 chart
可视化代码如下
新疆棉花产量年年上升,其它省份年年下降…
最后 Pyforest 还提供了一些函数来了解库的使用情况
# 返回已导入并且正在使用的库列表
print(pyforest.active_imports())
——————————–
[‘import pandas as pd’, ‘import requests as req’, ‘import pyg2plot’]
# 返回pyforest中所有Python库的列表
print(pyforest.lazy_imports())
——————————–
[‘import glob’, ‘import numpy as np’, ‘import matplotlib.pyplot as plt’…]
只有代码中有使用到的库,程序才会 import 进去,否则不会导入的哦!
/ 03 / 总结
好了,到此本期的分享就结束了
使用 Pyforest 库有时候确实是可以节省一些时间,不过也是有弊端存在的。比如调试的时候(大型项目),可能会很痛苦,不知道是哪里来的库
所以建议大家,在一些独立的脚本程序中使用,效果应该还是不错的
我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典