2013-06-17 3 views
0

나는 플래시와 PHP로 멀티 플레이어 게임을 제작 중이다. 때때로 두 명의 사용자가 같은 PHP 스크립트를 동시에 호출 할 수 있습니다. 이 스크립트는 데이터베이스에 정보를 기록하도록 설계되었습니다. 그러나 해당 정보가 이미 다른 사용자가 작성한 경우 스크립트를 실행하면 안됩니다. 그렇지 않으면 게임이 중단됩니다. PHP가 이러한 스크립트를 순차적으로 처리하는 경우 (MySQL이 여러 쿼리를 큐에 대기시키는 것과 유사), 하나의 스크립트 만 총을 실행해야하며 모든 것이 잘되어야합니다.여러 PHP 스크립트를 동시에 실행할 수 있습니까?

그러나 나는 그 시간의 약 10 %를 발견하고, 두 사용자의 스크립트가 실행됩니다. 내 이론은 서버가 때로는 정확히 동일한 시간에 스크립트를 실행하기위한 두 사용자 요청을 모두받으며 두 가지 모두 검색된 것이 데이터베이스에 아직 기록되지 않았기 때문에 둘 다 실행된다는 것입니다. 두 스크립트가 동시에 실행될 수 있습니까? 그렇다면이 문제에 대한 가능한 해결책은 무엇입니까?

+0

서버 구성에 따라 다르지만 일반적으로 가능합니다. – Maerlyn

+0

은 동시성 제어를 구현합니다. – DevZer0

+0

더 간단한 해결책 중 하나는 스크립트 시작 부분에 플래그를 넣고 끝날 때 꺼내는 것입니다. 스크립트가 플래그가 켜져 있으면 스크립트가 중지합니다. 이 플래그는 예를 들어 데이터베이스 필드, 외부 파일 등일 수 있습니다. – Voitcus

답변

0

그럴 가능성이 매우 높습니다. database transactions을 살펴보십시오.

간단히 말해 데이터베이스 트랜잭션은 데이터베이스에 동시에 액세스하는 프로그램 간의 동시성을 제어하는 ​​데 사용됩니다. 트랜잭션을 시작한 다음 여러 쿼리를 실행하고 마지막으로 트랜잭션을 커밋합니다. 두 스크립트가 서로 겹치면 그 중 하나가 실패합니다.

격리 수준은 두 개 (또는 그 이상)의 경쟁 스크립트가 공유 할 수있는 양을 세밀하게 제어 할 수 있음을 참고하십시오. 일반적으로 모두 데이터베이스에서 준비 할 수 있지만 쓰기 만 허용됩니다. 따라서 최종 커밋에서 오류가 발생합니다. 데이터베이스에서 모든 부작용이 발생하는 한 괜찮습니다. 외부 부작용 (예 : 파일 삭제 또는 전자 메일 보내기)이 있으면 충분하지 않습니다. 이 경우 거래 기간 동안 lock a table 또는 row으로 설정하거나 isolation level으로 설정할 수 있습니다.

+0

MySQL은 한 번에 두 개 이상의 쿼리로 행을 편집 할 수 없다는 것을 이해합니다. 다른 쿼리로 해당 행을 편집 할 때 행이 잠겨 있기 때문입니다. 그러나 문제는 PHP가 여러 스크립트를 동시에 실행할 수 있다는 것입니다. 이 스크립트는 데이터베이스를 쿼리하고 행이 비어 있음을 감지하므로 둘 중 하나만 실행하려고 할 때 스크립트를 실행하고 서로를 덮어 씁니다. – user2028200

+0

이것이 바로 트랜잭션이 당신을 보호 할 수있는 시나리오 유형입니다. – troelskn

0

PHP, C, Java라면 문제가되지 않습니다. 동시에 을 실행할 수있는 최대 프로세스 수는 CPU (및 코어)가 최대 인 경우입니다. 당신은 단지 2 개의 코어를 가지고 있다면, 100 개의 프로세스를 동시에 실행할 수 있습니다. 2 명만 실행 중이며 나머지는 대기 중입니다.

이제는 에 표시되는 내용에 따라을 실행합니다. 당신이 그것을 적극적으로 받아들이거나 기다리는 과정을 취하는 경우. 둘째, 시스템 구성, 대기 할 수있는 프로세스 수 및 시스템 사양에 따라 다릅니다.

+0

이것은 두 개의 분리 된 중단되지 않은 프로세스에 관한 것이 아니라 단일 CPU에서 발생할 수있는 경쟁 조건에 관한 것입니다. –

1

실제로 가능합니다. 스크립트의 시작과 끝에서 테이블 잠금 및 잠금 해제를 시도 할 수 있습니다.

잠긴 테이블의 잠금이 해제 될 때까지 기다려야하므로 일부 요청의 속도가 느려지므로

0

다음은 DB를 처음 가져 오는 첫 번째 PHP 스레드가 마지막으로 해제 할 때까지 (잠금 이름 "awesome_lock_row"를 사용하여) 테이블을 잠그도록 사용할 수있는 SQL 테이블 잠금의 예입니다. 두 번째 쓰레드는 동일한 테이블을 사용하려고 시도하고, 잠금 이름도 "awesome_lock_row"이기 때문에 첫 번째 PHP 쓰레드가 테이블 잠금을 해제 할 때까지 대기한다.

이 예제의 경우 동일한 스크립트를 cron 작업으로 동시에 100 번 실행하면 "update_this_data"number 필드 증가분이 100으로 표시됩니다. 테이블이 잠겨 있지 않은 경우 모든 동시 100 개의 스레드 아마 처음으로 동시에 0으로 "update_this_data"를 참조 것이며, 최종 결과는 1 대신이 도움이 (100)

<?php 
$db = new mysqli('host', 'username', 'password', 'dbname'); 

// Lock the table 
$db->query("DO GET_LOCK('awesome_lock_row', 30)"); // Timeout 30 seconds 

$result = $db->query("SELECT * FROM table_name"); 
if($result) { 
    if ($row = $result->fetch_object()) 
     $output = $row; 
    $result->close(); 
} 

$update_id = $output->some_id; 

$db->query(UPDATE table_name SET update_this_data=update_this_data+1 WHERE id={$update_id}); 

// Unlock the table 
$db->query("DO RELEASE_LOCK('awesome_lock_row')"); 
?> 

희망했을 것이다.

관련 문제