2011-02-10 38 views
6

Tôi có một dự án trong đó người dùng tải lên một hình ảnh thông qua biểu mẫu và máy chủ thực hiện một số hình thu nhỏ. Quá trình tạo hình thu nhỏ rất chậm nên tôi nghĩ rằng việc thay đổi kích thước hình ảnh bằng chức năng không chặn có thể là một giải pháp tốt. Ý tôi là: quá trình máy chủ biểu mẫu (có nhiều trường) cung cấp phản hồi "ok" cho người dùng và sau đó gọi hàm thu nhỏ. Làm thế nào tôi có thể làm điều đó?Chức năng không chặn PHP

Cảm ơn trước

+0

liên quan, không nhất thiết phải là một bản sao: http://stackoverflow.com/questions/124462/asynchronous-php-calls – Bobby

Trả lời

6

Tùy chọn tốt nhất của bạn là triển khai Gearman. Đó là một hệ thống Job Queue, nơi bạn có thể thực hiện đồng bộ các công việc không đồng bộ. http://gearman.org/

+0

Cảm ơn, tôi không biết Gearman, tôi sẽ kiểm tra. – LuisClemente

3

Bạn có thể có cronjob thực thi kịch bản thu nhỏ. Bạn có thể thêm hình ảnh để thay đổi kích thước trong một số loại hàng đợi (cơ sở dữ liệu mysql có lẽ) và kịch bản thu nhỏ chạy mỗi phút để kiểm tra xem có cái gì đó trong que và sau đó bắt đầu thay đổi kích thước.

+1

việc crno làm việc kỳ diệu, nhưng đôi khi bạn don không có quyền truy cập cron trên máy chủ. Có nhiều cách để giữ cho PHP xử lý sau khi người dùng đã được trả lời. – cromestant

+0

Cảm ơn câu trả lời của bạn. Vấn đề là tôi không thể chờ đợi cho đến khi quá trình cronjob hình ảnh, tôi cần các hình thu nhỏ ngay sau khi tải lên nhưng tôi không muốn người dùng tải chúng lên cho đến khi các ngón tay cái được tạo ra. – LuisClemente

+0

Bạn có thể viết lại nó thành 'daemon'. Đặt thời gian thực hiện tối đa thành 1 phút và tiếp tục kiểm tra xem có hình ảnh mới trong vòng lặp 'while (true)' hay không. Bằng cách này, kịch bản sẽ nhanh như chuyển đổi trực tiếp và nó sẽ không bị chặn. – gnur

6

Giải pháp tốt hơn tôi thường sử dụng: Tạo hình thu nhỏ động khi cần, chứ không phải khi tải lên.

Bạn tạo một kịch bản mà tạo ra hình thu nhỏ một cách nhanh chóng, và tất cả các thẻ hình ảnh của bạn trỏ đến kịch bản này:

<img src="/thumbnail.php?image=foobar.jpg&size=150" /> 

này trì hoãn việc phát thumbnail cho đến khi nó là cần thiết và các công trình "không đồng bộ". Với một số phép thuật ghi đè .htaccess, bạn thậm chí có thể làm cho nó trông giống như một tệp hình ảnh bình thường và hình ảnh bộ nhớ đệm theo cách mà máy chủ Apache sẽ phục vụ chúng vào lần sau mà không cần gọi kịch bản lệnh.


Để được một chút chi tiết hơn, tôi sử dụng này cho hình ảnh lý lịch thành viên:

thẻ hình ảnh:

<img src="/img/users/123456/50.jpg" /> 

.htaccess:

<IfModule mod_rewrite.c> 
    RewriteEngine On 

    # Rewrites requests for user images to match directory structure. 
    # E.g.: URL /img/users/123456/50.jpg -> /img/users/123/123456/50.jpg 
    # Intermediate directory level is introduced to avoid cramming too many directories into the same directory. 
    RewriteRule ^img/users/(\d{1,3})(\d*)/(\d+\.\D+)$ img/users/$1/$1$2/$3 [nocase,last] 

    RewriteCond %{REQUEST_FILENAME} !-d 
    RewriteCond %{REQUEST_FILENAME} !-f 
    RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] 

</IfModule> 

này trước hết viết lại các yêu cầu hình ảnh đến một cấu trúc thư mục sâu hơn. Nếu hình ảnh tồn tại, Apache sẽ phục vụ nó như bình thường. Nếu không, ứng dụng thông thường của tôi sẽ được gọi. Trong ứng dụng, tôi định tuyến các URL /img/users/... đến một mô-đun kết thúc bằng hai phần thông tin: id người dùng 123456 và kích thước được yêu cầu 50. Sau đó nó sẽ tạo ra một hình ảnh thu nhỏ khoảng theo logic này: hình ảnh hồ sơ cá nhân

  1. Find cho người dùng 123456
  2. Tạo thumbnail kích thước yêu cầu
  3. Viết thumbnail để /img/users/123/123456/50.jpg, nơi nó sẽ được nhặt bởi Apache lần sau
  4. ảnh Output
+3

Điều đó thực sự có thể làm chậm mọi thứ nếu rất nhiều hình ảnh được tải lên rất thường xuyên ... hàng loạt là cách để làm điều này, IMPO. – xil3

+2

@ xil3 Nó không thực sự tạo ra bất kỳ sự khác biệt nào, máy chủ cũng sẽ bận. Chỉ là thời điểm thay đổi, không phải khối lượng công việc thực tế.Nó cũng đảm bảo rằng hình ảnh có sẵn khi cần thiết, không giống như công việc cron làm chậm sự sẵn có của hình ảnh. Đúng caching bộ nhớ của khóa học là phải, như tôi đã viết. – deceze

+2

Vâng, tôi đoán việc ghép đôi 2 giải pháp là tốt nhất - chỉ trong trường hợp các hình ảnh chưa được xử lý theo lô. – xil3

2

Trên một hệ thống, tôi đã nhìn thấy một quá trình nền độc lập làm cho hình thu nhỏ:

  • mẫu được xử lý bình thường, mà không tạo ra bất kỳ hình ảnh thu nhỏ ở tất cả
  • hình ảnh được đưa ra một cái tên độc đáo và sao chép vào một thư mục đặc biệt.
  • một mục cơ sở dữ liệu được tạo ra trong một bảng thumbnails, liên kết hình ảnh ban đầu và tên độc đáo mới, đánh dấu là "được thu nhỏ" kịch bản xử lý
  • dạng dừng lại để chăm sóc và tiếp tục với bất cứ điều gì khác nó cần phải làm.

Có quy trình nền độc lập (và cơ quan giám sát) liên tục xem thư mục đặc biệt đó (hầu hết các hệ điều hành đều có các công cụ khác nhau thông báo cho bạn khi nội dung của thư mục thay đổi); nếu nó tìm thấy một hình ảnh đó, nó sẽ:

  • tạo ra một hình ảnh thu nhỏ (chúng tôi đang sử dụng CLI ImageMagick cho rằng)
  • tiết kiệm nó ở một nơi khác
  • cập nhật cơ sở dữ liệu, thiết lập tình trạng hình ảnh như "thu nhỏ OK "(hay 'thất bại', nếu nó không có thể làm cho một)

Khi bạn cần hình thu nhỏ, đánh dấu vào bảng thumbnails - nếu hình ảnh không phải là 'thu nhỏ OK', cho thấy một giữ chỗ, nếu không có được sự chính xác tên hình thu nhỏ và hiển thị tên này.

Điều đó hiệu quả - hầu hết các hình thu nhỏ được tạo trong vòng vài giây, mà không làm chậm các tập lệnh hướng đến người dùng. Lưu ý rằng bạn sẽ cần phải bắt đầu kịch bản nền bằng cách nào đó - trong trường hợp này, có một cơ quan giám sát trong cron, khởi động lại kịch bản thu nhỏ nếu nó chết.


@yankee đối tượng rằng một số yếu tố phổ biến:

  • nó không phải là cần thiết cho quá trình Thumbnailer để chạy như một kịch bản nền - nếu bạn có thể sống với một phút của độ trễ trước khi bạn nhận được hình thu nhỏ, bạn có thể chạy nó như là một kịch bản cron, loại bỏ hoàn toàn cơ quan giám sát.
  • ImageMagick được chọn trên GD vì lý do hiệu suất cụ thể; trình thu nhỏ có thể sử dụng bất kỳ phương thức nào khả dụng.

Chỉnh sửa: Tôi đã kiểm tra trang web và có thêm một cơ chế nữa - điều này là không cần thiết và bổ sung thêm chút tải, nhưng trông rất tuyệt, đặc biệt nếu bạn không mong đợi tải trang đầy đủ. trên các trang web AJAX-driven):

  • nơi một "không-không-nhưng-không-thumbnail" giữ chỗ là đầu ra, hình thu nhỏ được hiển thị trong một img với class="nothumb"
  • một hàm JS kiểm tra cho hình ảnh với này lớp
  • nếu tìm thấy, nó sẽ định kỳ kiểm tra xem hình thu nhỏ có đã có sẵn chưa
  • giữ chỗ tĩnh được thay thế bằng placeholders "tải"
  • nếu tìm thấy, nó sẽ thay thế các placeholder với thumbnail

này nạp hình thu nhỏ ngay sau khi họ đã sẵn sàng, với chi phí một số tài nguyên. Đối với một quá trình nền liên tục, nó không thực sự cần thiết; nhưng nếu bạn muốn đảm bảo rằng người dùng sẽ thấy hình thu nhỏ khi chúng trở nên có sẵn thay vì trên lần tải trang tiếp theo của họ, đây là một bổ sung hữu ích.

+0

Đây là một giải pháp hiệu quả, nhưng tiếc là đòi hỏi rất nhiều đặc quyền trên máy chủ không thường có sẵn cho các nhà phát triển php. – yankee

+0

@yankee: tốt, nó có thể sẽ không hoạt động trên lưu trữ được chia sẻ, điều đó chắc chắn - nhưng các phần tử "không phổ biến" duy nhất tôi thấy là 1) ImageMagick và 2) cron script, có thể 3) một quá trình nền dài (mà không thực sự cần thiết - có thể chạy dưới dạng tập lệnh cron). Không bao giờ có vấn đề với bất kỳ điều nào, ngoại trừ trên webhost rẻ nhất. – Piskvor

+0

@Piskvor: Nếu bạn làm điều đó như cron nó dễ dàng hơn tất nhiên, nhưng sẽ chi phí một số chậm trễ cho đến khi các hình thu nhỏ được tạo ra. Tôi đang băn khoăn về quy trình nền tảng dài hạn. Tôi nghĩ rằng hầu hết các hosters không cho phép bạn ghi đè lên thời gian thực hiện tối đa (bởi quá nhiều) mặc dù. Điều đó có thật không? Và tất nhiên bạn có thể sẽ không thể nhận được một móc hệ thống cho bạn biết khi một thư mục thay đổi sẽ thực sự hiệu quả. Mặc dù các phương tiện khác của IPC có thể được sử dụng. Tôi đoán TCP là giải pháp IPC di động nhất mà không bị trì hoãn cho đến khi thu nhỏ được thông báo ... Dù sao tôi thích ý tưởng của bạn – yankee

0

Gợi ý:

  1. Đóng kết nối của bạn trước khi kịch bản chấm dứt như được nêu ở đây: http://www.php.net/manual/en/features.connection-handling.php#71172

  2. Tạo đầu ra trong "thời gian thực" như đã giải thích ở đây: How to echo output in real time, (before script finishes)? (sẽ không làm việc trong tất cả môi trường và người dùng sẽ vẫn nhận được thanh tải cho đến khi hình thu nhỏ hoàn tất để tạo)

  3. Bắt đầu một chuyên gia khác cess tạo hình thu nhỏ cho bạn. Nếu bạn có các đặc quyền theo hệ thống sử dụng máy chủ() cho điều đó. Nếu bạn không có chúng, hãy tạo một tập lệnh php khác trên máy chủ mà bạn gọi bằng URL và ổ cắm. Sau đó, bạn có thể chấm dứt kết nối sớm và giữ cho tập lệnh chạy để tạo hình thu nhỏ. Sử dụng ignore_user_abort() để ngừng tạo hình thu nhỏ để hủy bỏ khi bạn hủy bỏ kết nối tcp được mở bằng ổ cắm của bạn.

2

Bạn có thể sử dụng tiêu đề http để cho khách hàng biết rằng đầu ra đã kết thúc sau khi thông báo "OK" đã được chuyển, trong khi vẫn giữ tập lệnh chạy trên máy chủ để xử lý hình thu nhỏ. Tôi đã sử dụng một lần thành công mã này:

header("Connection: close"); 
@ob_end_clean(); 
ignore_user_abort(); 
ob_start(); 

//generate and print server response here 
echo "everything OK"; 

$size = ob_get_length(); 
header("Content-Length: ".$size); 
ob_end_flush(); 
flush(); 

//whatever you do here has no influence on the page loading time, as the client has already closed its connection. 
generateThumbnail(); 
+0

Tuôn ra có thể không phải lúc nào cũng trả lại kết quả đầu ra - Tôi đã có nhiều kinh nghiệm với nó, dựa trên tải. – xil3

+0

Cảm ơn câu trả lời của bạn, nó có thể là một giải pháp nhưng tôi đang sử dụng Symfony và tôi không chắc chắn nếu tôi có thể làm điều đó. – LuisClemente

+0

Bạn chỉ cần thử nó. xil3 là completeley đúng, flush() không hoạt động như mong đợi trên tất cả các hệ thống và thiết lập (mặc dù trong trường hợp của tôi nó làm việc khá đáng tin cậy). Tuy nhiên, đây là một cách tiếp cận không an toàn, vì vậy nếu nội dung không được xóa đúng, mọi thứ vẫn hoạt động như mong đợi, người dùng sẽ chỉ phải đợi lâu hơn cho thông báo thành công. – Simon

0

Có thực sự là một cách, Nếu bạn gửi lại các tiêu đề phản ứng và nội dung trả lời, bạn thực sự có thể giữ sợi chỉ máy chủ đi với xử lý của bạn mà không giữ khách hàng đang đi. Vì vậy, bạn có thể gửi tiêu đề trở lại với loại nội dung vv .. hoặc chuyển hướng tiêu đề, v.v. trình duyệt sẽ đọc phản hồi. Nhưng điều đó không có nghĩa là luồng máy chủ dừng lại.,

Bạn có thể sử dụng trạng thái kết nối, người dùng bỏ qua hủy và giữ nguyên cùng một chủ đề trong máy chủ here bạn có thể thấy điều này được giải thích.

mẫu từ liên kết được cung cấp:

<?php 
ob_end_clean(); 
header("Connection: close\r\n");  
header("Content-Encoding: none\r\n"); 
ignore_user_abort(true); // optional 
ob_start(); 
echo ('Text user will see'); 
$size = ob_get_length(); 
header("Content-Length: $size"); 
ob_end_flush();  // Strange behaviour, will not work 
flush();   // Unless both are called ! 
ob_end_clean(); 

//do processing here 
sleep(5); 

echo('Text user will never see'); 
//do some processing 
?>  
Các vấn đề liên quan