练习 循环与函数

问题

为了练习函数与循环,我们来实现一个平方根函数:用牛顿法实现平方根函数。

计算机通常使用循环来计算 x 的平方根。从某个猜测的值 z 开始,我们可以根据 z² 与 x 的近似度来调整 z,产生一个更好的猜测:

z -= (z*z - x) / (2*z)
重复调整的过程,猜测的结果会越来越精确,得到的答案也会尽可能接近实际的平方根。

在提供的 func Sqrt 中实现它。无论输入是什么,对 z 的一个恰当的猜测为 1。 要开始,请重复计算 10 次并随之打印每次的 z 值。观察对于不同的值 x(1、2、3 ...), 你得到的答案是如何逼近结果的,猜测提升的速度有多快。

背景知识

  1. 学习Go语言的for语法和函数定义。
  2. 先定义Sqrt函数,实现for语法的三部分,初始化、终止条件值、后置语句。
  3. for循环的三部分。
    初始化语句:在第一次迭代前执行
    条件表达式:在每次迭代前求值
    后置语句:在每次迭代的结尾执行
  4. 初始化语句和后置语句是可选的。
  5. 此时你可以去掉分号,因为 C 的 while 在 Go 中叫做 for。
  6. 如果省略循环条件,该循环就不会结束,因此无限循环可以写得很紧凑。

实现思路

  1. 实现一个Sqrt函数,传入float参数,返回一个float
  2. 选择一个合理的计算平方根的函数,在指定次数内计算出符合期望的结果。
  3. 简单设置误差为0.001。

实现代码

GitHub

文章链接

  1. 练习:循环与函数

消息队列的思考

什么是消息队列

维基百科的定义:在计算机科学中,消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常是来自用户。消息队列提供了异步的通信协议,每一个贮列中的纪录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列交互。消息会保存在队列中,直到接收者取回它。

这定义太复杂了。简单的来讲就是排队系统嘛。这好比,每天到了中午吃饭的点,去麦当劳或者肯德基,都是要排队的嘛,毕竟,员工的数量有限,中午想吃饭的人会很多。大家都会先下单,然后拿着号码去排队取餐。这就是队列啊。

消息队列应用场景

消息队列的应用场景是,当前业务处理量遇到瓶颈,无法及时处理业务,将部分耗时业务分离到消息队列异步处理,避免业务处理失败。
这好比有人在麦当劳点了1个经典套餐,另外一个人点了7个儿童套餐过生日,门店的员工会根据下单情况进行处理,做好经典套餐直接让第一个人来取,肯定不会说,先做完7个儿童套餐再处理第一个任务。

消息队列,可以解耦复杂业务的逻辑,但不可避免,降低了用户的体验。如果每次去麦当劳都需要排对下单,取餐,我想你以后也不大想去他们家吃饭了吧。

优势

队列的好处:
1. 增大的系统的吞吐量,可以处理更多的”请求”。
2. 不管是耗时任务还是即时任务,都可以得到较好的处理。

劣势

队列的劣势:
1. 由于消息队列的存在,任务变成了异步处理,处理完成的时间不可预知。
2. 既然有异步的处理,必然会有数据不一致的情况。

常用的消息队列

RabbitMQ

消息模式

支持消息模式 备注
简单队列 支持单一的消费者
工作队列 支持多个消费者
发布订阅 通过exchange获取队列,消费队列的消息
路由队列 exchange_type='direct' 必须exchange和routing_key匹配才可以消费消费。
主题队列 exchange_type='topic' 可实现队列模糊匹配
RPC 支持RPC调用消费

性能

  1. 根据性能测试第二部分 第一部分 大约在4w个消息每秒,开启ack+持久化后,几乎下降了10倍。该测试在2012年发布的,仅供参考。

实现原理

  1. RabbitMQ是基于AMQP(Advanced Message Queuing Protocol,高级消息队列协议)实现的消息中间件。实现的语言是erlang。
  2. 常用较多的是路由模式。可以实现精确的消息匹配,只需要获取自定义的消息。

PHP支持

  1. 安装Composer包 php-amqplib/php-amqplib
  2. PHP扩展

Kafka

消费模式

暂时只支持一种topics。支持多个消费者,支持分组,可以平均分布消息到不同的分区。

性能

  1. 官方在2014年也做了性能测试。单机达到了80k消息每秒。官方性能测试 文章地址
  2. 可以说是为了性能而存在的消息队列。
  3. Kafka并不保证消息顺序,也不支持数据持久化,部署依赖zookeeper组件实现分布式。

实现原理

Kafka底层是Java实现的。

PHP支持

  1. 优先推荐PHP扩展 rdkafka 主要就基于librdkafka开发的PHP客户端。
  2. 也有相关的Composer包,该包不支持snappy压缩方式的消息。

参考链接

  1. 消息队列及常见消息队列介绍
  2. 消息队列
  3. RabbitMQ和Kafka

MaxWell的学习

什么是MaxWell?

MaxWell守护进程是读取MySQL的二进制日志,将更新操作写入到消息队列,例如Kafka,RabbitMQ,Redis的订阅发布的应用。

官网上的示例1,在数据库test的表maxwell插入了一条数据,那么你在名为maxwell的topics会接收到一条消息,含有数据库、表、时间戳、更新类型等字段。

mysql> insert into `test`.`maxwell` set id = 1, daemon = 'Stanislaw Lem';
  maxwell: {
    "database": "test",
    "table": "maxwell",
    "type": "insert",
    "ts": 1449786310,
    "xid": 940752,
    "commit": true,
    "data": { "id":1, "daemon": "Stanislaw Lem" }
  }

示例2,更新语句也是类似的。不同的是,更新的消息会多一个字段old,记录字段尚未被更新之前的数据。

 mysql> update test.maxwell set daemon = 'firebus!  firebus!' where id = 1;
  maxwell: {
    "database": "test",
    "table": "maxwell",
    "type": "update",
    "ts": 1449786341,
    "xid": 940786,
    "commit": true,
    "data": {"id":1, "daemon": "Firebus!  Firebus!"},
    "old":  {"daemon": "Stanislaw Lem"}
  }

生产者

MaxWell支持多种生产者,官网自带配置文档。以Kafka为例,默认会把消息发送到名为maxwell的topics,你也可以自定义配置

踩坑

在MaxWell启动后,Kafka的生产者可以进行高性能的配置。如果添加以下的配置

kafka.acks = 1
kafka.compression.type = snappy
kafka.retries=0

消息会以snappy的方式进行压缩。什么是snappy压缩方式
在采用Composer包nmred/kafka-php消费消息时,遇到MaxWell生产的消息无法读取。
后来定位到是该Composer包不支持snappy压缩的消息,更换为php-rdkafka的扩展即可。

参考链接

  1. Kafka 0.9 Configuration Best Practices
  2. Manually Installing the extension