挨踢 | 石武浩

石武浩的博客

shiwuhao

for foreach while性能比较

一般情况下,遍历一个数组有三种方法,for、while、foreach。其中最简单方便的是foreach。那么它们在操作和性能上存在什么差别,通常使用那种方法比较好。
下面先让我们来测试一下共同遍历一个有50000个下标的一维数组所耗的时间;

测试平台:
CPU:2.6 GHz Intel Core i5
内存:8 GB 1600 MHz DDR3
硬盘:256 SSD
OS:OS X El Capitan
WEB:Apache/2.4.16 (Unix) php 5.4

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
/**
 * Created by PhpStorm.
 * User: shiwuhao
 * Date: 15/11/12
 * Time: 17:05
 */




$arr = array();

for($i = 0; $i < 50000; $i++) {
    $arr[] =  $i * rand(1000,9999);
}


/**
 * for
 */

$str = '';
$start_time = getRunTime();

for($i = 0; $i < count($arr); $i++) {
    $str .= $arr[$i];
}

$end_time = getRunTime();
$time_used = $end_time - $start_time;

echo 'for : '.$time_used.'<br />';

unset($start_time, $end_time, $str, $time_used);

/**
 * while
 */

$str = '';
$start_time = getRunTime();

while(list($key, $val) = each($arr)) {
    $str .= $val;
}

$end_time = getRunTime();
$time_used = $end_time - $start_time;

echo 'while : '.$time_used.'<br />';

unset($start_time, $end_time, $str, $time_used);


/**
 * foreach
 */

$str = '';
$start_time = getRunTime();

foreach ($arr as $k => $v) {
    $str .= $v;
}

$end_time = getRunTime();
$time_used = $end_time - $start_time;

echo 'foreach : '.$time_used.'<br />';

unset($start_time, $end_time, $str, $time_used);



/**
 * 获取执行时间
 * @return float
 */

function getRunTime()
{

    list($usec,$sec)=explode(" ",microtime());
    return ((float)$usec+(float)$sec);
}

输出结果:

for : 0.050076007843018
while : 0.066652059555054
foreach : 0.012237071990967

结果表明,对于遍历同样一个数组,foreach速度最快,最慢的则是while。

PHP设计模式-策略模式

策略模式属于行为类模式中的一个类型

适用场景:
当我们实用的类比较简单,但是有相互不关联,只是在特定行为上有所差异的场景下,策略模式就会十分有用。

在策略模式中,从一个接口扩展出许多具体的类,这些具体的类用于一些特定的对象。

策略模式的三个角色:
1.抽象策略角色
2.具体策略角色
3.环境角色(对抽象策略角色的引用)

举个例子:
对多维数组进行排序,并且使用对象来实现它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?php
/**
 * 策略模式实现数组排序
 * Created by PhpStorm.
 * User: shiwuhao
 * Date: 15/11/5
 * Time: 23:49
 */


/**
 * 排序的接口定义sort方法
 * Interface iSort
 */

interface iSort{

    function sort(array $list);
}

/**
 * 多维数组按字符串排序
 * Class MultiAlphaSort
 */

class MultiAlphaSort implements iSort {

    // 排序方式
    private $_order;

    // 排序索引
    private $_index;

    public function __construct($index, $order = 'ascending')
    {
        $this->_index = $index;
        $this->_order = $order;
    }

    // 实现排序功能
    public function sort(array $list)
    {
        if ($this->_order == 'ascending') {
            uasort($list, array($this, 'ascSort'));
        } else {
            uasort($list, array($this, 'descSort'));
        }
        return $list;
    }

    // 按自然排序法升序排序
    public function ascSort($x, $y)
    {
        return strnatcmp($x[$this->_index], $y[$this->_index]);
    }

    // 按自然排序法降序排序
    public function descSort($x, $y)
    {
        return strnatcmp($y[$this->_index], $x[$this->_index]);
    }
}

/**
 * 多维数组按照数字排序
 * Class MultiNumberSort
 */

class MultiNumberSort implements iSort
{

    // 排序索引
    private $_index;

    // 排序方式
    private $_order;

    public function __construct($index, $order = 'ascending')
    {
        $this->_index = $index;
        $this->_order = $order;
    }

    // 实现排序功能
    public function sort(array $list)
    {
        if ($this->_order == 'ascending') {
            uasort($list, array($this, 'ascSort'));
        } else {
            uasort($list, array($this, 'descSort'));
        }
        return $list;
    }

    // 比较两个值大小 升序排序
    public function ascSort($x, $y)
    {
        return $x[$this->_index] > $y[$this->_index];
    }

    // 比较两个值大小 降序排序
    public function descSort($x, $y)
    {
        return $x[$this->_index] < $y[$this->_index];
    }
}

阅读更多

PHP设计模式-组合模式

组合模式属于结构型模式。
先来说说组合模式的几个特点:
1:必须存在不可分割的元素
2:组合后的物体可以被组合

举个通俗的例子:
雇员和团队,团队是由雇员组成,工作可以分配给两者中的任意一个,也可以由任意一个来完成改工作。

创建文件 WorkUnit.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
/**
 * 定义一个任务包 采用组合模式
 * 也定义一个团队和员工类 分配任务
 * Created by PhpStorm.
 * User: shiwuhao
 * Date: 15/11/5
 * Time: 17:36
 */


/**
 * 任务类
 * Class WorkUnit
 */

abstract class WorkUnit{

    // 存储任务
    protected $tasks = array();

    // 存储员工名称 或 团队名称
    protected $name = NULL;

    // 构造函数指定名称
    public function __construct($name)
    {
        $this->name = $name;
    }

    // 返回团队 或 员工 名称
    public function getName()
    {
        return $this->name;
    }

    // 要实现的抽象函数
    abstract function add(Employee $e);
    abstract function remove(Employee $e);
    abstract function assignTask($task);
    abstract function completeTask($task);
}

/**
 * 团队类
 */

class Team extends WorkUnit{

    // 存储团队成员
    private $_employees = array();

    // 添加一个团队成员
    public function add(Employee $e)
    {
        $this->_employees[] = $e;
        echo '<p>已将'.$e->getName().'添加到团队『'.$this->getName().'』中</p>';
    }

    // 移除一个团队成员
    public function remove(Employee $e)
    {
        $index = array_search($e, $this->_employees);
        unset($this->_employees[$index]);
        echo '<p>已将'.$e->getName().'从团队『'.$this->getName().'』移出</p>';
    }

    // 分配任务
    public function assignTask($task)
    {
        $this->tasks[] = $task;
        echo '<p>一个新的任务分配给团队『'.$this->getName().'』, 团队共有'.$this->getCount().'名成员</p>';
    }

    // 完成任务
    public function completeTask($task)
    {
        $index = array_search($task, $this->tasks);
        unset($this->tasks[$index]);
        echo '<p>'.$task.' 任务已经完成,完成团队『'.$this->getName().'』</p>';
    }

    // 返回团队成员数量
    public function getCount()
    {
        return count($this->_employees);
    }
}

/**
 * 员工类
 */

class Employee extends WorkUnit{

    public function add(Employee $e)
    {
        return false;
    }

    public function remove(Employee $e)
    {
        return false;
    }

    // 分配任务
    public function assignTask($task)
    {
        $this->tasks[] = $task;
        echo '<p>'.$task.' 任务分配给'.$this->getName().'</p>';
    }

    // 完成任务
    public function completeTask($task)
    {
        $index = array_search($task, $this->tasks);
        unset($this->tasks[$index]);
        echo '<p>'.$task.' 任务已完成, 操作人'.$this->getName().'</p>';
    }
}

创建文件 index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
/**
 * 使用组合模式类
 * Created by PhpStorm.
 * User: shiwuhao
 * Date: 15/11/5
 * Time: 18:22
 */


require './WorkUnit.php';

// 创建一个团队
$myTeam = new Team('myTeam');

// 创建几个员工
$user1 = new Employee('user1');
$user2 = new Employee('user2');
$user3 = new Employee('user3');

// 为团队添加成员
$myTeam->add($user1);
$myTeam->add($user2);

// 给团队分配任务
$myTeam->assignTask('做一些事情');

// 给员工分配任务
$user3->assignTask('做点事情');

/*****因为使用了组合模式,四个对象可以同等对待*****/

// 团队完成任务
$myTeam->completeTask('做一些事情');

// 团队移除成员
$myTeam->remove($user1);

PHP设计模式-工厂模式

工厂模式多用于创建多种不同类型的类的多个对象

适用场景:当程序编写的时候,并不能确定在生成对象的时候其确切的对象类型,只有当程序运行的时候才会确定

一个工厂模式的变种是抽象工厂模式。然而工厂模式输出不同的对象,每一个都继承同一个父类,抽象工厂则输出这些工厂类。

工厂模式的好处:
1、将创建实例的工作与使用实例的工作分开
2、把初始化实例时的工作放到工厂里进行,使代码更容易维护。
3、使得修改代码时不会引起太大的变动,良好的扩展性

工厂类 Shape.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
/**
 * 获取一个形状的周长和面积  工厂模式
 * Created by PhpStorm.
 * User: shiwuhao
 * Date: 15/11/5
 * Time: 14:45
 */


require './shape/Rectangle.php';
require './shape/Triangle.php';

abstract class ShapeFactory{

    /**
     * 创建形状 根据类型值创建不同的对象
     * @param $type
     * @param array $sizes
     * @return Rectangle|Triangle
     */

    static function Create($type, array $sizes)
    {
        switch($type) {
            case 'rectangle' :
                return new Rectangle($sizes[0], $sizes[1]);
                break;

            case 'triangle' :
                return new Triangle($sizes[0], $sizes[1], $sizes[2]);
                break;
        }
    }
}

阅读更多

PHP设计模式-单例模式

单例模式是一种创建型模式,它会限制应用程序,使其只能创建某一特定类类型的一个单一的实例。

1:新建Config.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Config
{
    // 存储单个实例
    static private $_instance = NULL;

    // 存储配置信息
    private $_setting = array();

    // 私有的构造方法 防止被外部实例
    private function __construct(){}

    // 私有的克隆方法 防止被外部实例
    private function __clone(){}

    // 实例返回方法
    static function getInstance()
    {
        if (self::$_instance == NULL) {
            self::$_instance = new Config();
        }

        return self::$_instance;
    }

    // 定义设置配置的方法
    public function set($index, $value)
    {
        $this->_setting[$index] = $value;
    }

    // 定义获取配置的方法
    public function get($index)
    {
        return $this->_setting[$index];
    }
}

阅读更多

Redis发布及订阅消息

Redis 的 pub sub可以实现邮件系统,发送者(在 Redis 术语中被称为发布者)发送的邮件,而接收器(用户)接收它们。由该消息传送的链路被称为信道。

开启三个连接进行测试
连接1作为发布端
连接2,连接3作为接受端

连接2订阅 msg1 消息

1
2
3
4
5
127.0.0.1:6379> subscribe msg1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "msg1"
3) (integer) 1

连接3订阅 msg1 msg2 消息

1
2
3
4
5
6
7
8
127.0.0.1:6379> subscribe msg1 msg2
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "msg1"
3) (integer) 1
1) "subscribe"
2) "msg2"
3) (integer) 2

连接1进行消息发布

1
2
publish msg1 asdfghjklqwertyuio
(integer) 2

连接2接收结果

1
2
3
1) "message"
2) "msg1"
3) "asdfghjklqwertyuio"

连接3接收结果

1
2
3
1) "message"
2) "msg1"
3) "asdfghjklqwertyuio"

连接1进行消息发布

1
2
127.0.0.1:6379> publish msg2 1111111111111111111111111111111
(integer) 1

连接2接收结果

1
// 没有接受到消息

连接3接收结果

1
2
3
1) "message"
2) "msg2"
3) "1111111111111111111111111111111"

Redis持久化机制

Redis支持两种持久化方法:
1:snapshotting 快照方式(默认)
快照方式是默认的持久化方式,这种方式将内存中的数据已快照的方式写入到二进制文件中,默认的文件名为dump.rdb。
我们可以通过修改配置文件的方式配置Redis在N秒内如果超过M个key修改就自动做快照。

1
2
3
4
5
6
[root@localhost bin]# vi /usr/local/redis/etc/redis.conf

// 搜索save
save 900 1       // 900秒内超过1个key被修改,发起快照保存
save 300 10      // 300秒内超过10个key被修改,发起快照保存
save 60 10000    // 60秒内超过10000个key被修改,发起快照保存

2:append-only file aof方式
aof比快照方式有更好的持久化性,是由于aof时,Redis会将每一个收到的写命令通过write函数追加到文件中,当Redis重启时,会通过重新执行文件中保存的命令在内存中重建整个数据库的内容

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost bin]# vi /usr/local/redis/etc/redis.conf
// 启用aof持久化方式
appendonly yes
// aof文件名
appendfilename "appendonly.aof"

// 收到命令就立即写入磁盘,最慢,但是保证完全的持久化
# appendfsync always
// 每秒钟写入磁盘一次,性能和持久化方面比较折中
appendfsync everysec
// 完全依赖系统,性能最好,持久化没保证
# appendfsync no

Redis实现乐观锁

使用watch监控key,对key实现加锁

假设有个age的key,我们开两个连接进行赋值操作

连接一 监控age,开始事务,复制操作,先不执行exec

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 10
QUEUED
127.0.0.1:6379> get age
QUEUED

连接二 直接执行赋值操作

1
2
127.0.0.1:6379> set age 100
OK

回到连接一,执行exec操作,此时age值已被连接2改变,事务执行失败

1
2
3
4
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get age
"100"

事务处理——Redis学习笔记

Redis对事务的支持还比较简单。Redis只能保证一个client发起的事务中的命令可以连续执行,而中间不会插入其他client的命令。当一个client在一个连接中发出 multi 命令时,这个连接会进入一个事务上下文,该连接的后续命令不会立即执行,二十先放到一个队列中,当执行 exec 命令时,Redis会顺序执行队列中的所有命令。

1:multi
事务开始

2:exec
执行multi发出所有命令

3:discard
取消事务

5:watch
监视一个或多个key

6:unwatch
取消监视

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> set name shiwuhao
QUEUED
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> incr version
QUEUED
127.0.0.1:6379> exec
1) OK
2) "shiwuhao"
3) (integer) 1

Redis主从复制 提示:Error condition on socket for SYNC: No route to host

从服务器启动Redis提示 “Error condition on socket for SYNC: No route to host” 解决方案

1
2
3
20309:S 03 Oct 18:26:28.358 * Connecting to MASTER 10.211.55.6:6379
20309:S 03 Oct 18:26:28.358 * MASTER <-> SLAVE sync started
20309:S 03 Oct 18:26:28.359 # Error condition on socket for SYNC: No route to host

一般出现该问题是由(主服务器)防火墙引起的

解决方案
1:关掉主服务器防火墙
临时关闭:service iptables stop 永久关闭:chkconfig iptables off

2:防火墙打开端口
#/sbin/iptables -I INPUT -p tcp –dport 6379 -j ACCEPT
#/etc/init.d/iptables save
#service iptables restart

下一页

程序猿,爱游戏,爱电影,爱折腾
邮箱:admin@shiwuhao.com