Hướng dẫn php handle long process - xử lý php quá trình dài

89

Mới! Lưu câu hỏi hoặc câu trả lời và sắp xếp nội dung yêu thích của bạn. Tìm hiểu thêm.
Learn more.

Tôi có một tập lệnh PHP mất nhiều thời gian (5-30 phút) để hoàn thành. Chỉ trong trường hợp nó quan trọng, tập lệnh đang sử dụng Curl để cạo dữ liệu từ một máy chủ khác. Đây là lý do nó mất quá nhiều thời gian; Nó phải chờ mỗi trang tải trước khi xử lý nó và chuyển sang trang tiếp theo.

Tôi muốn có thể bắt đầu tập lệnh và để nó cho đến khi hoàn thành, nó sẽ đặt cờ trong bảng cơ sở dữ liệu.

Những gì tôi cần biết là làm thế nào để có thể kết thúc yêu cầu HTTP trước khi tập lệnh được hoàn thành. Ngoài ra, có phải là một tập lệnh PHP là cách tốt nhất để làm điều này?

hỏi ngày 6 tháng 2 năm 2010 lúc 9:16Feb 6, 2010 at 9:16

Hướng dẫn php handle long process - xử lý php quá trình dài

Kbanmankbanmankbanman

4.1736 Huy hiệu vàng31 Huy hiệu bạc40 Huy hiệu đồng6 gold badges31 silver badges40 bronze badges

2

Chắc chắn nó có thể được thực hiện với PHP, tuy nhiên bạn không nên làm điều này như một nhiệm vụ nền - quy trình mới phải được phân tách khỏi nhóm quy trình nơi nó được bắt đầu.

Vì mọi người tiếp tục đưa ra câu trả lời sai tương tự cho Câu hỏi thường gặp này, tôi đã viết một câu trả lời đầy đủ hơn ở đây:

http://symcbean.blogspot.com/2010/02/php-and-long-running-processes.html

Từ các ý kiến:

Phiên bản ngắn là shell_exec('echo /usr/bin/php -q longThing.php | at now'); nhưng lý do "tại sao", hơi dài để đưa vào đây.

Cập nhật +12 năm

Mặc dù đây vẫn là một cách tốt để gọi một chút mã chạy dài, nhưng việc bảo mật sẽ hạn chế hoặc thậm chí vô hiệu hóa khả năng của PHP trong máy chủ web để khởi chạy các tệp thực thi khác. Và vì điều này phân tách hành vi của việc chạy nhật ký từ đó đã bắt đầu nó, trong nhiều trường hợp, có thể thích hợp hơn khi sử dụng một công việc daemon hoặc cron.

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 23:35Feb 6, 2010 at 23:35

Symcbeansymcbeansymcbean

47K6 Huy hiệu vàng57 Huy hiệu bạc90 Huy hiệu Đồng6 gold badges57 silver badges90 bronze badges

14

Cách nhanh chóng và bẩn sẽ là sử dụng chức năng ignore_user_abort trong PHP. Điều này về cơ bản nói: Không quan tâm người dùng làm gì, hãy chạy tập lệnh này cho đến khi nó được hoàn thành. Điều này có phần nguy hiểm nếu đó là một trang web đối diện công cộng (vì có thể, cuối cùng bạn có 20 phiên bản của tập lệnh chạy cùng một lúc nếu nó được bắt đầu 20 lần).

Cách "sạch" (ít nhất là IMHO) là đặt cờ (ví dụ như trong DB) khi bạn muốn bắt đầu quy trình và chạy cronjob mỗi giờ (hoặc hơn) để kiểm tra xem cờ đó có được đặt không. Nếu nó được đặt, tập lệnh chạy dài bắt đầu, nếu nó không được đặt, không phải là điều xảy ra.

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 9:26Feb 6, 2010 at 9:26

FlorianhflorianhFlorianH

3.0341 Huy hiệu vàng18 Huy hiệu bạc15 Huy hiệu đồng1 gold badge18 silver badges15 bronze badges

2

Bạn có thể sử dụng EXEC hoặc hệ thống để bắt đầu một công việc nền, sau đó thực hiện công việc đó.

Ngoài ra, có những cách tiếp cận tốt hơn để quét web mà bạn đang sử dụng. Bạn có thể sử dụng một cách tiếp cận luồng (nhiều luồng thực hiện một trang cùng một lúc) hoặc một lần sử dụng Eventloop (một chủ đề thực hiện nhiều trang tại thời điểm). Cách tiếp cận cá nhân của tôi bằng cách sử dụng Perl sẽ sử dụng bất kỳ :: http.

ETA: Symcbean giải thích cách tách quá trình nền đúng cách ở đây.

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 9:49Feb 6, 2010 at 9:49

Leon Timmermansleon TimmermansLeon Timmermans

29,9k2 Huy hiệu vàng63 Huy hiệu bạc110 Huy hiệu Đồng2 gold badges63 silver badges110 bronze badges

1

Không, PHP không phải là giải pháp tốt nhất.

Tôi không chắc chắn về Ruby hay Perl, nhưng với Python, bạn có thể viết lại cào trên trang của mình để được nhiều luồng và nó có thể sẽ chạy nhanh hơn ít nhất 20 lần. Viết các ứng dụng đa luồng có thể là một thách thức, nhưng ứng dụng Python đầu tiên tôi đã viết là máy quét trang Mutlti-Thread. Và bạn có thể chỉ cần gọi tập lệnh Python từ trong trang PHP của mình bằng cách sử dụng một trong các hàm thực thi shell.

Hướng dẫn php handle long process - xử lý php quá trình dài

Rộng

12.7k6 Huy hiệu vàng39 Huy hiệu bạc63 Huy hiệu Đồng6 gold badges39 silver badges63 bronze badges

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 9:35Feb 6, 2010 at 9:35

Hướng dẫn php handle long process - xử lý php quá trình dài

Jamiebjamiebjamieb

9.69713 Huy hiệu vàng46 Huy hiệu bạc62 Huy hiệu Đồng13 gold badges46 silver badges62 bronze badges

4

Có, bạn có thể làm điều đó trong PHP. Nhưng ngoài PHP, sẽ là khôn ngoan khi sử dụng Trình quản lý hàng đợi. Đây là chiến lược:

  1. Chia nhỏ nhiệm vụ lớn của bạn thành các nhiệm vụ nhỏ hơn. Trong trường hợp của bạn, mỗi nhiệm vụ có thể tải một trang duy nhất.

  2. Gửi từng nhiệm vụ nhỏ đến hàng đợi.

  3. Chạy nhân viên xếp hàng của bạn ở đâu đó.

Sử dụng chiến lược này có những lợi thế sau:

  1. Đối với các nhiệm vụ chạy dài, nó có khả năng phục hồi trong trường hợp một vấn đề nghiêm trọng xảy ra ở giữa cuộc chạy - không cần phải bắt đầu từ đầu.

  2. Nếu các tác vụ của bạn không phải chạy tuần tự, bạn có thể chạy nhiều công nhân để chạy các tác vụ cùng một lúc.

Bạn có nhiều tùy chọn khác nhau (đây chỉ là một vài):

  1. RabbitMQ (https://www.rabbitmq.com/tutorials/tutorial-one-phph.html)
  2. Zeromq (http://zeromq.org/bindings:php)
  3. Nếu bạn đang sử dụng khung Laravel, hàng đợi được tích hợp (https://laravel.com/docs/5.4/queues), với trình điều khiển cho AWS SES, Redis, Beanstalkd

Đã trả lời ngày 23 tháng 5 năm 2017 lúc 5:06May 23, 2017 at 5:06

Aljo Faljo faljo f

2.28021 Huy hiệu bạc22 Huy hiệu đồng21 silver badges22 bronze badges

PHP có thể hoặc không phải là công cụ tốt nhất, nhưng bạn biết cách sử dụng nó và phần còn lại của ứng dụng của bạn được viết bằng cách sử dụng nó. Hai phẩm chất này, kết hợp với thực tế là PHP là "đủ tốt" tạo ra một trường hợp khá mạnh để sử dụng nó, thay vì Perl, Ruby hoặc Python.

Nếu mục tiêu của bạn là học một ngôn ngữ khác, thì hãy chọn một ngôn ngữ và sử dụng nó. Bất kỳ ngôn ngữ bạn đã đề cập sẽ làm công việc, không có vấn đề. Tôi tình cờ thích Perl, nhưng những gì bạn thích có thể khác.

Symcbean có một số lời khuyên tốt về cách quản lý các quy trình nền tại liên kết của mình.

Nói tóm lại, viết một tập lệnh CLI PHP để xử lý các bit dài. Hãy chắc chắn rằng nó báo cáo trạng thái theo một cách nào đó. Tạo một trang PHP để xử lý các bản cập nhật trạng thái, bằng cách sử dụng AJAX hoặc các phương thức truyền thống. Tập lệnh khởi động của bạn sẽ bắt đầu quá trình chạy trong phiên riêng của mình và trả về xác nhận rằng quá trình này đang diễn ra.

Chúc may mắn.

Đã trả lời ngày 8 tháng 2 năm 2010 lúc 6:28Feb 8, 2010 at 6:28

Daotoaddaotoaddaotoad

26.4K7 Huy hiệu vàng58 Huy hiệu bạc99 Huy hiệu đồng7 gold badges58 silver badges99 bronze badges

Tôi đồng ý với các câu trả lời nói rằng điều này nên được chạy trong một quy trình nền. Nhưng điều quan trọng là bạn phải báo cáo về trạng thái để người dùng biết rằng công việc đang được thực hiện.

Khi nhận được yêu cầu PHP để khởi động quy trình, bạn có thể lưu trữ trong cơ sở dữ liệu đại diện cho nhiệm vụ với một định danh duy nhất. Sau đó, bắt đầu quá trình xẹp màn hình, chuyển nó là định danh duy nhất. Báo cáo lại cho ứng dụng iPhone rằng tác vụ đã được bắt đầu và nó nên kiểm tra một URL được chỉ định, chứa ID tác vụ mới, để có trạng thái mới nhất. Ứng dụng iPhone hiện có thể thăm dò ý kiến ​​(hoặc thậm chí "Thăm dò ý kiến ​​dài") URL này. Trong khi đó, quy trình nền sẽ cập nhật biểu diễn cơ sở dữ liệu của tác vụ khi nó hoạt động với tỷ lệ phần trăm hoàn thành, bước hiện tại hoặc bất kỳ chỉ số trạng thái nào khác bạn muốn. Và khi nó đã hoàn thành, nó sẽ đặt một lá cờ hoàn thành.

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 19:58Feb 6, 2010 at 19:58

Hướng dẫn php handle long process - xử lý php quá trình dài

JacobjacobJacob

76.3K24 Huy hiệu vàng146 Huy hiệu bạc226 Huy hiệu Đồng24 gold badges146 silver badges226 bronze badges

Bạn có thể gửi nó dưới dạng yêu cầu XHR (AJAX). Khách hàng thường không có thời gian chờ cho XHR, không giống như các yêu cầu HTTP thông thường.

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 23:51Feb 6, 2010 at 23:51

Hướng dẫn php handle long process - xử lý php quá trình dài

JaljalJAL

21.1k1 Huy hiệu vàng46 Huy hiệu bạc66 Huy hiệu đồng1 gold badge46 silver badges66 bronze badges

Tôi nhận ra đây là một câu hỏi khá cũ nhưng muốn cho nó một phát súng. Kịch bản này cố gắng giải quyết cả cuộc gọi khởi động ban đầu để hoàn thành nhanh chóng và cắt giảm tải nặng thành các khối nhỏ hơn. Tôi đã không kiểm tra giải pháp này.

 'http://exemple.com',
    2 => 'http://exemple1.com',
    3 => 'http://exemple2.com',
    4 => 'http://exemple3.com',
    // ... and so on.
  );

  // Returns the first one on the list.
  foreach ($query_result as $id => $url) {
    return $url;
  }
  return FALSE;
}

function update_remote_sources_to_crawl($id) {
  // Update my database or log file list so the $id record wont show up
  // on my next call to get_remote_sources_to_crawl()
}

$crawling_source = get_remote_sources_to_crawl();

if ($crawling_source) {


  // Run your scraping code on $crawling_source here.


  if ($your_scraping_has_finished) {
    // Update you database or log file.
    update_remote_sources_to_crawl($id);

    $ctx = stream_context_create(array(
      'http' => array(
        // I am not quite sure but I reckon the timeout set here actually
        // starts rolling after the connection to the remote server is made
        // limiting only how long the downloading of the remote content should take.
        // So as we are only interested to trigger this script again, 5 seconds 
        // should be plenty of time.
        'timeout' => 5,
      )
    ));

    // Open a new connection to this script and close it after 5 seconds in.
    file_get_contents('http://' . $_SERVER['HTTP_HOST'] . '/crawler.php', FALSE, $ctx);

    print 'The cronjob kick off has been initiated.';
  }
}
else {
  print 'Yay! The whole thing is done.';
}

Đã trả lời ngày 27 tháng 6 năm 2013 lúc 1:24Jun 27, 2013 at 1:24

Francisco Luzfrancisco LuzFrancisco Luz

2.6132 Huy hiệu vàng24 Huy hiệu bạc35 Huy hiệu Đồng2 gold badges24 silver badges35 bronze badges

5

Tôi muốn đề xuất một giải pháp khác một chút so với Symcbean, chủ yếu là vì tôi có yêu cầu bổ sung rằng quy trình chạy dài cần được chạy như một người dùng khác chứ không phải là người dùng Apache / WWW-DATA.

Giải pháp đầu tiên sử dụng Cron để thăm dò bảng nhiệm vụ nền:

  • Trang web PHP chèn vào bảng tác vụ nền, trạng thái 'đã gửi'
  • Cron chạy một lần mỗi 3 phút, sử dụng một người dùng khác, chạy tập lệnh PHP CLI kiểm tra bảng tác vụ nền cho các hàng 'đã gửi'
  • PHP CLI sẽ cập nhật cột trạng thái trong hàng vào 'xử lý' và bắt đầu xử lý, sau khi hoàn thành, nó sẽ được cập nhật thành 'đã hoàn thành'

Giải pháp thứ hai sử dụng cơ sở Linux Inotify:

  • Trang web PHP cập nhật tệp điều khiển với các tham số do người dùng đặt và cũng cung cấp ID tác vụ
  • Shell Script (với tư cách là người dùng không phải WWW) đang chạy Inotifywait sẽ đợi tệp điều khiển được viết
  • Sau khi tệp điều khiển được viết, một sự kiện Close_Write sẽ được nêu ra, tập lệnh Shell sẽ tiếp tục
  • script shell thực hiện php CLI để thực hiện quá trình chạy dài
  • PHP CLI ghi đầu ra vào tệp nhật ký được xác định bởi ID tác vụ hoặc cập nhật thay thế tiến trình trong bảng trạng thái
  • Trang web PHP có thể thăm dò tệp nhật ký (dựa trên ID tác vụ) để hiển thị tiến trình của quy trình chạy dài hoặc nó cũng có thể truy vấn bảng trạng thái

Một số thông tin bổ sung có thể được tìm thấy trong bài viết của tôi: http://inventorsparadox.blogspot.co.id/2016/01/long-rick-process-in-linux-using-php.html

Đã trả lời ngày 31 tháng 1 năm 2016 lúc 12:32Jan 31, 2016 at 12:32

Tôi đã làm những điều tương tự với Perl, Double Fork () và tách ra khỏi quy trình cha mẹ. Tất cả công việc tìm nạp HTTP nên được thực hiện trong quy trình nĩa.

Đã trả lời ngày 6 tháng 2 năm 2010 lúc 19:41Feb 6, 2010 at 19:41

Alexandr Ciorniialexandr CiorniiAlexandr Ciornii

7.2961 Huy hiệu vàng25 Huy hiệu bạc29 Huy hiệu đồng1 gold badge25 silver badges29 bronze badges

Sử dụng proxy để ủy thác yêu cầu.

Đã trả lời ngày 29 tháng 10 năm 2010 lúc 22:17Oct 29, 2010 at 22:17

Zerodinzerodinzerodin

8495 Huy hiệu bạc9 Huy hiệu Đồng5 silver badges9 bronze badges

Những gì tôi luôn sử dụng là một trong những biến thể này (bởi vì các hương vị khác nhau của Linux có các quy tắc khác nhau về việc xử lý đầu ra/một số chương trình đầu ra khác nhau):

Biến thể i @Exec ('./ myscript.php \ 1>/dev/null \ 2>/dev/null &'); @exec('./myscript.php \1>/dev/null \2>/dev/null &');

Biến thể II @Exec ('php -f myscript.php \ 1>/dev/null \ 2>/dev/null &'); @exec('php -f myscript.php \1>/dev/null \2>/dev/null &');

Biến thể III @Exec ('Nohup myscript.php \ 1>/dev/null \ 2>/dev/null &'); @exec('nohup myscript.php \1>/dev/null \2>/dev/null &');

Bạn có thể cài đặt "Nohup". Nhưng ví dụ, khi tôi đang tự động hóa các cuộc trò chuyện video FFMPEG, giao diện đầu ra bằng cách nào đó không được xử lý 100% bằng cách chuyển hướng các luồng đầu ra 1 & 2, vì vậy tôi đã sử dụng Nohup và chuyển hướng đầu ra.

Đã trả lời ngày 7 tháng 9 năm 2011 lúc 10:42Sep 7, 2011 at 10:42

Bác sĩ Burnsdr Burnsdr burns

511 Huy hiệu bạc2 Huy hiệu đồng1 silver badge2 bronze badges

Nếu bạn có tập lệnh dài thì hãy phân chia trang hoạt động với sự trợ giúp của tham số đầu vào cho mỗi tác vụ. (Sau đó, mỗi trang hoạt động như luồng) tức là nếu trang có 1 LAC sản phẩm từ ma thuật hoặc cornjobpage.php (ví dụ sau)

Và đối với nhân viên nền, tôi nghĩ rằng bạn nên thử kỹ thuật này, nó sẽ giúp gọi nhiều trang bạn thích tất cả các trang sẽ chạy cùng một lúc mà không chờ đợi mỗi phản hồi trang không đồng bộ.

cornjobpage.php // mainpage

    
            

testpage.php

     testValue
    ?>

PS: Nếu bạn muốn gửi các tham số URL dưới dạng vòng lặp thì hãy theo dõi câu trả lời này: https: //stackoverflow.com/a/41225209/6295712

Đã trả lời ngày 19 tháng 12 năm 2016 lúc 15:32Dec 19, 2016 at 15:32

Hướng dẫn php handle long process - xử lý php quá trình dài

Hassan Saeedhassan SaeedHassan Saeed

5.3631 Huy hiệu vàng 30 Huy hiệu bạc35 Huy hiệu Đồng1 gold badge30 silver badges35 bronze badges

Không phải là cách tiếp cận tốt nhất, như nhiều người đã nêu ở đây, nhưng điều này có thể giúp ích:

ignore_user_abort(1); // run script in background even if user closes browser
set_time_limit(1800); // run it for 30 minutes

// Long running script here

Đã trả lời ngày 29 tháng 1 năm 2019 lúc 19:27Jan 29, 2019 at 19:27

Hướng dẫn php handle long process - xử lý php quá trình dài

Lucas Bustamantelucas BustamanteLucas Bustamante

Phù vàng 14.6K7 Huy hiệu vàng82 Huy hiệu đồng7 gold badges82 silver badges81 bronze badges

Nếu đầu ra mong muốn của tập lệnh của bạn là một số xử lý, không phải là một trang web, thì tôi tin rằng giải pháp mong muốn là chạy tập lệnh của bạn từ shell, chỉ đơn giản là

php my_script.php

Đã trả lời ngày 13 tháng 9 năm 2019 lúc 9:35Sep 13, 2019 at 9:35

Hướng dẫn php handle long process - xử lý php quá trình dài

MrmartinmrmartinMrMartin

3734 Huy hiệu bạc18 Huy hiệu đồng4 silver badges18 bronze badges