PHP의 일반적인 동시성 시나리오에 대한 솔루션

王林
풀어 주다: 2023-04-07 19:38:02
원래의
2433명이 탐색했습니다.

PHP의 일반적인 동시성 시나리오에 대한 솔루션

일반적인 해결 방법은 다음과 같습니다.

1. 대기열을 사용하여 대기열을 처리합니다. 동시 요청은 대기열에 배치되고 추가 프로세스에 의해 순차적으로 처리됩니다. , 그러나 추가 프로세스 지원 및 처리 지연이 심각하므로 이 문서에서는 이 방법에 대해 먼저 논의하지 않습니다.

2. 데이터베이스의 트랜잭션 특성을 사용하여 원자성 업데이트를 수행합니다. 이 방법은 데이터베이스의 트랜잭션 특성에 의존해야 합니다.

3. 파일 단독 잠금 기능을 이용하면 주문 요청 처리 시 Flock을 이용해 파일을 잠글 수 있습니다.

1. Redis 트랜잭션 기능 활용

redis 트랜잭션은 원자성 작업이므로 주문 처리 중에 다른 동시 프로세스에 의해 데이터가 수정되지 않도록 할 수 있습니다.

샘플 코드:

<?php
$http = new swoole_http_server("0.0.0.0", 9509);  // 监听 9509
 
$http->set(array(
  &#39;reactor_num&#39; => 2, //reactor thread num
  &#39;worker_num&#39; => 4  //worker process num
));
 
$http->on(&#39;request&#39;, function (swoole_http_request $request, swoole_http_response $response) {
  $uniqid = uniqid(&#39;uid-&#39;, TRUE);  // 模拟唯一用户ID
  $redis = new Redis();
  $redis->connect(&#39;127.0.0.1&#39;, 6379);  // 连接 redis
 
  $redis->watch(&#39;rest_count&#39;); // 监测 rest_count 是否被其它的进程更改
 
  $rest_count = intval($redis->get("rest_count")); // 模拟唯一订单ID
  if($rest_count > 0){
    $value = "{$rest_count}-{$uniqid}"; // 表示当前订单,被当前用户抢到了
 
    // do something ... 主要是模拟用户抢到单后可能要进行的一些密集运算
    $rand = rand(100, 1000000);
    $sum=0;
    for ($i=0;$i<$rand;$i++){ $sum+=$i; }
 
   // redis 事务
    $redis->multi();
    $redis->lPush(&#39;uniqids&#39;, $value);
    $redis->decr(&#39;rest_count&#39;);
    $replies = $redis->exec(); // 执行以上 redis 事务
 
   // 如果 rest_count 的值被其它的并发进程更改了,以上事务将回滚
    if(!$replies){
      echo "订单 {$value} 回滚".PHP_EOL;
    }
  }
  $redis->unwatch();
});
 
$http->start();
로그인 후 복사

ab test 사용

$ ab -t 20 -c 10 http://192.168.1.104:9509/
로그인 후 복사

2. 파일 배타적 잠금 사용(차단 모드)

차단 모드에서 해당 프로세스가 파일 배타적 잠금을 획득 중이고 다른 프로세스가 잠금을 점유 중인 경우, this 프로세스는 정지되어 다른 프로세스가 잠금을 해제할 때까지 기다린 다음 잠금 자체를 획득한 후 실행을 계속합니다.

샘플 코드:

<?php
$http = new swoole_http_server("0.0.0.0", 9510);
 
$http->set(array(
  &#39;reactor_num&#39; => 2, //reactor thread num
  &#39;worker_num&#39; => 4  //worker process num
));
 
$http->on(&#39;request&#39;, function (swoole_http_request $request, swoole_http_response $response) {
 
  $uniqid = uniqid(&#39;uid-&#39;, TRUE);
  $redis = new Redis();
  $redis->connect(&#39;127.0.0.1&#39;, 6379);
 
  $fp = fopen("lock.txt", "w+");
 
  // 阻塞(等待)模式, 要取得独占锁定(写入的程序)
  if(flock($fp,LOCK_EX))  //锁定当前指针
  {
   // 成功取得锁后,放心处理订单
    $rest_count = intval($redis->get("rest_count"));
    $value = "{$rest_count}-{$uniqid}";
    if($rest_count > 0){
      // do something ...
      $rand = rand(100, 1000000);
      $sum=0;
      for ($i=0;$i<$rand;$i++){ $sum+=$i; }
 
      $redis->lPush(&#39;uniqids&#39;, $value);
      $redis->decr(&#39;rest_count&#39;);
    }
 
   // 订单处理完成后,再释放锁
    flock($fp,LOCK_UN);
  }
  fclose($fp);
 
});
 
$http->start();
로그인 후 복사

ab 테스트 사용

$ ab -t 20 -c 10 http://192.168.1.104:9510/
로그인 후 복사

추천 튜토리얼: PHP 튜토리얼

위 내용은 PHP의 일반적인 동시성 시나리오에 대한 솔루션의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿