抢购、秒杀是平常很常见的场景,面试的时候面试官也经常会问到,比如问你淘宝中的抢购秒杀是怎么实现的等等。

抢购、秒杀实现很简单,但是有些问题需要解决,主要针对两个问题:

一、高并发对数据库产生的压力
二、竞争状态下如何解决库存的正确减少("超卖"问题)

第一个问题,对于PHP来说很简单,用缓存技术就可以缓解数据库压力,比如memcache,redis等缓存技术。
第二个问题就比较复杂点:

常规写法:
查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数。

  1. <?php
  2. $conn=mysql_connect("localhost","big","123456");
  3. if(!$conn){
  4. echo "connect failed";
  5. exit;
  6. }
  7. mysql_select_db("big",$conn);
  8. mysql_query("set names utf8");
  9. $price=10;
  10. $user_id=1;
  11. $goods_id=1;
  12. $sku_id=11;
  13. $number=1;
  14. //生成唯一订单
  15. function build_order_no(){
  16. return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
  17. }
  18. //记录日志
  19. function insertLog($event,$type=0){
  20. global $conn;
  21. $sql="insert into ih_log(event,type)
  22. values('$event','$type')";
  23. mysql_query($sql,$conn);
  24. }
  25. //模拟下单操作
  26. //库存是否大于0
  27. $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
  28. //解锁 此时ih_store数据中goods_id='$goods_id' and sku_id='$sku_id' 的数据被锁住(注3),其它事务必须等待此次事务 提交后才能执行
  29. $rs=mysql_query($sql,$conn);
  30. $row=mysql_fetch_assoc($rs);
  31. if($row['number']>0){//高并发下会导致超卖
  32. $order_sn=build_order_no();
  33. //生成订单
  34. $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
  35. values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
  36. $order_rs=mysql_query($sql,$conn);
  37. //库存减少
  38. $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
  39. $store_rs=mysql_query($sql,$conn);
  40. if(mysql_affected_rows()){
  41. insertLog('库存减少成功');
  42. }else{
  43. insertLog('库存减少失败');
  44. }
  45. }else{
  46. insertLog('库存不够');
  47. }
复制代码
 

出现这种情况怎么办呢?来看几种优化方法:

优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false

  1. 1 //库存减少
  2. 2 $sql="update ih_store set number=number-{$number} where sku_id='$sku_id' and number>0";
  3. 3 $store_rs=mysql_query($sql,$conn);
  4. 4 if(mysql_affected_rows()){
  5. 5     insertLog('库存减少成功');6 }
复制代码
 

优化方案2:使用MySQL的事务,锁住操作的行

  1. <?php
  2. $conn=mysql_connect("localhost","big","123456");
  3. if(!$conn){
  4. echo "connect failed";
  5. exit;
  6. }
  7. mysql_select_db("big",$conn);
  8. mysql_query("set names utf8");
  9. $price=10;
  10. $user_id=1;
  11. $goods_id=1;
  12. $sku_id=11;
  13. $number=1;
  14. //生成唯一订单号
  15. function build_order_no(){
  16. return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
  17. }
  18. //记录日志
  19. function insertLog($event,$type=0){
  20. global $conn;
  21. $sql="insert into ih_log(event,type)
  22. values('$event','$type')";
  23. mysql_query($sql,$conn);
  24. }
  25. //模拟下单操作
  26. //库存是否大于0
  27. mysql_query("BEGIN");   //开始事务
  28. $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此时这条记录被锁住,其它事务必须等待此次事务提交后才能执行
  29. $rs=mysql_query($sql,$conn);
  30. $row=mysql_fetch_assoc($rs);
  31. if($row['number']>0){
  32. //生成订单
  33. $order_sn=build_order_no();
  34. $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
  35. values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
  36. $order_rs=mysql_query($sql,$conn);
  37. //库存减少
  38. $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
  39. $store_rs=mysql_query($sql,$conn);
  40. if(mysql_affected_rows()){
  41. insertLog('库存减少成功');
  42. mysql_query("COMMIT");//事务提交即解锁
  43. }else{
  44. insertLog('库存减少失败');
  45. }
  46. }else{
  47. insertLog('库存不够');
  48. mysql_query("ROLLBACK");
  49. }
复制代码
 

优化方案3:使用非阻塞的文件排他锁

  1. <?php
  2. $conn=mysql_connect("localhost","root","123456");
  3. if(!$conn){
  4. echo "connect failed";
  5. exit;
  6. }
  7. mysql_select_db("big-bak",$conn);
  8. mysql_query("set names utf8");
  9. $price=10;
  10. $user_id=1;
  11. $goods_id=1;
  12. $sku_id=11;
  13. $number=1;
  14. //生成唯一订单号
  15. function build_order_no(){
  16. return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
  17. }
  18. //记录日志
  19. function insertLog($event,$type=0){
  20. global $conn;
  21. $sql="insert into ih_log(event,type)
  22. values('$event','$type')";
  23. mysql_query($sql,$conn);
  24. }
  25. $fp = fopen("lock.txt", "w+");
  26. if(!flock($fp,LOCK_EX | LOCK_NB)){
  27. echo "系统繁忙,请稍后再试";
  28. return;
  29. }
  30. //下单
  31. $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
  32. $rs=mysql_query($sql,$conn);
  33. $row=mysql_fetch_assoc($rs);
  34. if($row['number']>0){//库存是否大于0
  35. //模拟下单操作
  36. $order_sn=build_order_no();
  37. $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
  38. values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
  39. $order_rs=mysql_query($sql,$conn);
  40. //库存减少
  41. $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
  42. $store_rs=mysql_query($sql,$conn);
  43. if(mysql_affected_rows()){
  44. insertLog('库存减少成功');
  45. flock($fp,LOCK_UN);//释放锁
  46. }else{
  47. insertLog('库存减少失败');
  48. }
  49. }else{
  50. insertLog('库存不够');
  51. }
  52. fclose($fp);
复制代码
 

优化方案4:使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是)
先将商品库存如队列

  1. <?php
  2. $store=1000;
  3. $redis=new Redis();
  4. $result=$redis->connect('127.0.0.1',6379);
  5. $res=$redis->llen('goods_store');
  6. echo $res;
  7. $count=$store-$res;
  8. for($i=0;$i<$count;$i++){
  9. $redis->lpush('goods_store',1);
  10. }
  11. echo $redis->llen('goods_store');
复制代码
 

抢购、描述逻辑

  1. <?php
  2. $conn=mysql_connect("localhost","big","123456");
  3. if(!$conn){
  4. echo "connect failed";
  5. exit;
  6. }
  7. mysql_select_db("big",$conn);
  8. mysql_query("set names utf8");
  9. $price=10;
  10. $user_id=1;
  11. $goods_id=1;
  12. $sku_id=11;
  13. $number=1;
  14. //生成唯一订单号
  15. function build_order_no(){
  16. return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
  17. }
  18. //记录日志
  19. function insertLog($event,$type=0){
  20. global $conn;
  21. $sql="insert into ih_log(event,type)
  22. values('$event','$type')";
  23. mysql_query($sql,$conn);
  24. }
  25. //模拟下单操作
  26. //下单前判断redis队列库存量
  27. $redis=new Redis();
  28. $result=$redis->connect('127.0.0.1',6379);
  29. $count=$redis->lpop('goods_store');
  30. if(!$count){
  31. insertLog('error:no store redis');
  32. return;
  33. }
  34. //生成订单
  35. $order_sn=build_order_no();
  36. $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
  37. values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
  38. $order_rs=mysql_query($sql,$conn);
  39. //库存减少
  40. $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
  41. $store_rs=mysql_query($sql,$conn);
  42. if(mysql_affected_rows()){
  43. insertLog('库存减少成功');
  44. }else{
  45. insertLog('库存减少失败');
  46. }
复制代码
 

上述只是简单模拟高并发下的抢购,真实场景要比这复杂很多,很多注意的地方,如抢购页面做成静态的,通过ajax调用接口。

再如上面的会导致一个用户抢多个,思路:
需要一个排队队列和抢购结果队列及库存队列。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列。
我之间做商城项目的时候,在秒杀这一块我直接用的redis,这段时间看了看上面的几种方法,虽然各有不同,但是实现目的都一样的,各位自己选择,开心就好。

抢购、秒杀是平常很常见的场景,面试的时候面试官也经常会问到,比如问你淘宝中的抢购秒杀是怎么实现的等等。

抢购、秒杀实现很简单,但是有些问题需要解决,主要针对两个问题:

一、高并发对数据库产生的压力

二、竞争状态下如何解决库存的正确减少("超卖"问题)

 

第一个问题,对于PHP来说很简单,用缓存技术就可以缓解数据库压力,比如memcache,redis等缓存技术。

第二个问题就比较复杂点:

常规写法:

查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数。

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
<?php
$conn=mysql_connect("localhost","big","123456");
if(!$conn){
    echo "connect failed";
    exit;
}
mysql_select_db("big",$conn);
mysql_query("set names utf8");
  
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
  
//生成唯一订单
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysql_query($sql,$conn);
}
  
//模拟下单操作
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
//解锁 此时ih_store数据中goods_id='$goods_id' and sku_id='$sku_id' 的数据被锁住(注3),其它事务必须等待此次事务 提交后才能执行
$rs=mysql_query($sql,$conn);
$row=mysql_fetch_assoc($rs);
if($row['number']>0){//高并发下会导致超卖
    $order_sn=build_order_no();
    //生成订单
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
    $order_rs=mysql_query($sql,$conn);
      
    //库存减少
    $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
    $store_rs=mysql_query($sql,$conn);
    if(mysql_affected_rows()){
        insertLog('库存减少成功');
    }else{
        insertLog('库存减少失败');
    }
}else{
    insertLog('库存不够');
}

出现这种情况怎么办呢?来看几种优化方法:

优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false

1
2
3
4
5
1 //库存减少
2 $sql="update ih_store set number=number-{$number} where sku_id='$sku_id' and number>0";
3 $store_rs=mysql_query($sql,$conn);
4 if(mysql_affected_rows()){
5     insertLog('库存减少成功');6 }

优化方案2:使用MySQL的事务,锁住操作的行

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
<?php
$conn=mysql_connect("localhost","big","123456");
if(!$conn){
    echo "connect failed";
    exit;
}
mysql_select_db("big",$conn);
mysql_query("set names utf8");
  
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
  
//生成唯一订单号
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysql_query($sql,$conn);
}
  
//模拟下单操作
//库存是否大于0
mysql_query("BEGIN");   //开始事务
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此时这条记录被锁住,其它事务必须等待此次事务提交后才能执行
$rs=mysql_query($sql,$conn);
$row=mysql_fetch_assoc($rs);
if($row['number']>0){
    //生成订单
    $order_sn=build_order_no();
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
    $order_rs=mysql_query($sql,$conn);
      
    //库存减少
    $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
    $store_rs=mysql_query($sql,$conn);
    if(mysql_affected_rows()){
        insertLog('库存减少成功');
        mysql_query("COMMIT");//事务提交即解锁
    }else{
        insertLog('库存减少失败');
    }
}else{
    insertLog('库存不够');
    mysql_query("ROLLBACK");
}

优化方案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
<?php
$conn=mysql_connect("localhost","root","123456");
if(!$conn){
    echo "connect failed";
    exit;
}
mysql_select_db("big-bak",$conn);
mysql_query("set names utf8");
  
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
  
//生成唯一订单号
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysql_query($sql,$conn);
}
  
$fp = fopen("lock.txt", "w+");
if(!flock($fp,LOCK_EX | LOCK_NB)){
    echo "系统繁忙,请稍后再试";
    return;
}
//下单
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
$rs=mysql_query($sql,$conn);
$row=mysql_fetch_assoc($rs);
if($row['number']>0){//库存是否大于0
    //模拟下单操作
    $order_sn=build_order_no();
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
    $order_rs=mysql_query($sql,$conn);
      
    //库存减少
    $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
    $store_rs=mysql_query($sql,$conn);
    if(mysql_affected_rows()){
        insertLog('库存减少成功');
        flock($fp,LOCK_UN);//释放锁
    }else{
        insertLog('库存减少失败');
    }
}else{
    insertLog('库存不够');
}
fclose($fp);

优化方案4:使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是)

先将商品库存如队列

1
2
3
4
5
6
7
8
9
10
11
<?php
$store=1000;
$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);
$res=$redis->llen('goods_store');
echo $res;
$count=$store-$res;
for($i=0;$i<$count;$i++){
    $redis->lpush('goods_store',1);
}
echo $redis->llen('goods_store');

抢购、描述逻辑

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
<?php
$conn=mysql_connect("localhost","big","123456");
if(!$conn){
    echo "connect failed";
    exit;
}
mysql_select_db("big",$conn);
mysql_query("set names utf8");
  
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
  
//生成唯一订单号
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysql_query($sql,$conn);
}
  
//模拟下单操作
//下单前判断redis队列库存量
$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);
$count=$redis->lpop('goods_store');
if(!$count){
    insertLog('error:no store redis');
    return;
}
  
//生成订单
$order_sn=build_order_no();
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=mysql_query($sql,$conn);
  
//库存减少
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=mysql_query($sql,$conn);
if(mysql_affected_rows()){
    insertLog('库存减少成功');
}else{
    insertLog('库存减少失败');
}

上述只是简单模拟高并发下的抢购,真实场景要比这复杂很多,很多注意的地方,如抢购页面做成静态的,通过ajax调用接口。

再如上面的会导致一个用户抢多个,思路:

需要一个排队队列和抢购结果队列及库存队列。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列。

我之间做商城项目的时候,在秒杀这一块我直接用的redis,这段时间看了看上面的几种方法,虽然各有不同,但是实现目的都一样的,各位自己选择,开心就好。

PHP和Redis实现在高并发下的抢购及秒杀功能示例详解的更多相关文章

  1. php结合redis实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...

  2. (高级篇)php结合redis实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...

  3. php结合redis实现高并发下的抢购、秒杀功能 (转载)

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到 ...

  4. 【转】php结合redis实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...

  5. php 结合redis实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...

  6. Redis实现高并发下的抢购、秒杀功能

    博主最近在项目中遇到了抢购问题!现在分享下.抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖" ...

  7. php结合redis实现高并发下的抢购、秒杀功能【转】

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...

  8. php结合redis实现高并发下的抢购、秒杀功能 (转)

      抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易 ...

  9. PHP开发中多种方案实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到 ...

随机推荐

  1. 2019-04-12-day031-进程基础

    操作系统的发展历程 主要的人机矛盾是什么 : CPU的使用率 输入\输出数据和CPU计算没有关系 操作系统是怎么进化的 传统的纸带输入 磁带的存储降低了输入输出数据占用的时间,提高了CPU的利用率 多 ...

  2. Open Nginx gzip

    默认情况下,Nginx的gzip压缩是关闭的, gzip压缩功能就是可以让你节省不少带宽,但是会增加服务器CPU的开销哦,Nginx默认只对text/html进行压缩 ,如果要对html之外的内容进行 ...

  3. Java并发--Java线程面试题 Top 50

    原文链接:http://www.importnew.com/12773.html 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Ja ...

  4. How to Install Tomcat 8.0.27 on CentOS/RHEL and Ubuntu【转】

    https://tecadmin.net/install-tomcat-8-on-centos-rhel-and-ubuntu/ Apache Tomcat is an opensource web ...

  5. java服务端的 极光推送

    项目中用到了极光推送  下面写下笔记 首先引入jar包   下载地址https://docs.jiguang.cn/jpush/resources/(非maven项目的下载地址) <depend ...

  6. 深入学习Motan系列(四)—— 客户端

    困惑的袋鼠,对框架的把握有些茫然,但是仍然一步步向前,行动总比一直迷茫停止不前要好,您说呢,各位客官? 这篇开始客户端的分析.有些地方的代码,就不每段都标出了,中间有跳跃的地方,请自己对照代码来看.鄙 ...

  7. Python数据存储:pickle模块的使用讲解

    在机器学习中,我们常常需要把训练好的模型存储起来,这样在进行决策时直接将模型读出,而不需要重新训练模型,这样就大大节约了时间.Python提供的pickle模块就很好地解决了这个问题,它可以序列化对象 ...

  8. PHP使用文件锁解决高并发问题示例

    新建一个.txt文件,文件中什么都不用写. [一].阻塞(等待)模式:(只要有其他进程已经加锁文件,当前进程会一直等其他进程解锁文件) <?php //连接数据库 $con=mysqli_con ...

  9. 2018年,Java程序员转型大数据开发,是不是一个好选择?

    近日网上有一篇关于Java程序员职场生存现状的文章“2017年 Java 程序员,风光背后的危机”,在Java程序员圈子里引起了广泛关注和热议. 2017年,Java 程序员面临更加激烈的竞争. 不得 ...

  10. django模板语言循环字典,及forloop

    views: from django.shortcuts import render,redirect from django.shortcuts import HttpResponse # Crea ...