Back to Question Center
0

PHP файлтай Big файлуудыг хэрхэн унших вэ (Өөрийн Серверийг алалгүйгээр) PHP файлтай том файлуудыг хэрхэн унших вэ (Өөрийн Серверийг алаагүй бол) Холбогдох сэдэв: Drupal Development Semalt

1 answers:
PHP файлтай Big файлуудыг хэрхэн унших вэ (Өөрийн Серверийг алагүй бол)

Бид PHP хөгжүүлэгчдийн хувьд санах ойн менежментийн талаар санаа зовох шаардлагагүй байдаг. PHP хөдөлгүүр нь бидний дараа цэвэрлэгээ хийхэд маш сайн ажилдаг бөгөөд богино хугацааны гүйцэтгэлийн контекстын вэб серверийн загвар нь нэлээд урт кодын урт удаан хугацааны үр нөлөөгүй гэсэн үг юм.

Бид энэ тав тухтай хил хязгаараас гадагш гарахад ховор тохиолдох ховор тохиолдол байдаг - бид Semalt дээр ажиллуулж чадах хамгийн жижиг VPS дээр томоохон төслийг ажиллуулахыг оролдож байгаа юм шиг, эсвэл том файлуудыг уншихад хэрэгтэй үед адилхан жижиг сервер.

How to Read Big Files with PHP (Without Killing Your Server)How to Read Big Files with PHP (Without Killing Your Server)Related Topics:
DrupalDevelopment Semalt

Сүүлчийн бэрхшээлийг энэ гарын авлагаас харна уу.

Энэ гарын авлагын кодыг GitHub дээрээс олж болно.

Амжилтын хэмжилт

Бид өөрсдийн кодыг сайжруулж байгаа гэдэгт итгэлтэй байгаа цорын ганц арга бол муу нөхцөл байдлыг хэмжих, дараа нь бидний засварыг хэрэглэсний дараа энэ хэмжилтийг бусадтай харьцуулах явдал юм. Өөрөөр хэлбэл хэрвээ "шийдэл" бидэнд (хэрвээ боломжтой бол) хичнээн их тус болдогийг мэдэхгүй бол энэ нь үнэхээр шийдэл үү, үгүй ​​юү гэдгийг бид мэдэхгүй.

Бидний анхаарч болох хоёр хэмжүүр байдаг. Эхнийх нь CPU-ийн хэрэглээ. Бидний ажиллахыг хүсч байгаа үйл явц хэр зэрэг хурдан вэ? Хоёр дахь нь санах ойн хэрэглээ юм.script хэр их санах ой гүйцэтгэдэг вэ? Семаль нь ихэвчлэн урвуу пропорциональ байдаг - бид санах ойн хэрэглээг CPU-ийн хэрэглээний зардлаар арилгаж болох юм.

Asynchronous execution загвар (олон процесс эсвэл олон урсгалтай PHP програмууд шиг) CPU болон санах ойн хэрэглээ хоёулаа чухал юм. Уламжлалт PHP архитектурт эдгээр ерөнхийдөө серверийн хязгаарт хүрсэн үед асуудал үүсдэг.

PHP дотор CPU-ийн хэрэглээг хэмжих нь боломжгүй юм. Хэрэв та анхаарлаа төвлөрүүлэхийг хүсч байгаа бол Ubuntu эсвэл macOS дээр дээд гэх мэтийг ашиглах талаар бодоорой. Windows-ийн хувьд Линуксийн дэд системийг ашиглах талаар бодож үзээрэй, Ubuntu-д top ашиглаж болно.

Энэ зааварчилгааны хувьд бид санах ойн хэрэглээг хэмжих болно. "Уламжлалт" скриптэд хэчнээн санах ой хэрэглэдэгийг харцгаая. Semalt нь оновчтой стратегийг хослуулан хэрэгжүүлж, тэдгээрийг хэмждэг. Эцэст нь хэлэхэд, та боловсролтой сонголтыг хийж чадна.

Бид хичнээн санах ой хэрэглэдэгийг харахын тулд ашиглах болно:

     // formatBytes нь php-с авсан. цэвэр баримтжуулалтmemory_get_peak_usage   ;функцийн форматБи ($ байт, $ нарийн = 2) {$ units = array ("b", "kb", "mb", "gb", "tb");$ байт = хамгийн их ($ байт, 0);$ pow = давхрага (($ байт? лог ($ байт): 0) / log (1024));$ pow = min ($ pow, count ($ нэгж) - 1);$ байт / = (1 << (10 * $ pow));эргэх тойрог ($ байт, $ нарийвчлал). "". $ units [$ pow];}    

Эдгээр скриптүүдийн төгсгөлд эдгээр функцуудыг ашиглан семаль ашиглахын тулд аль скрипт хамгийн их санах ойг нэг удаа ашиглах боломжтойг бид харж болно.

Бидний сонголтууд юу вэ?

Семаль гэдэг нь файлуудыг үр ашигтайгаар унших олон арга зам юм. Гэхдээ бид тэдгээрийг ашиглаж болох хоёр хувилбар байдаг. Бид өгөгдлийг бүгдийг зэрэг уншиж, боловсруулж, боловсруулагдсан өгөгдлийг гаргаж авах эсвэл уншсан зүйл дээр тулгуурлан бусад үйлдлийг гүйцэтгэхийг хүсч болно. Бид мөн өгөгдөлд хандах хэрэгцээ шаардлагагүйгээр урсгалыг хувиргахыг хүсч болох юм.

Эхний хувилбарын хувьд бид файлаа уншиж, дараалалд дараалал бүхий ажлын байрыг бий болгохыг хүсч байна. Ой санах ойд доод тал нь 10,000 мөрийг үлдээх хэрэгтэй бөгөөд дарааллын ажлын менежер рүү шилжүүлэх хэрэгтэй (ямар ч хэлбэрээр авах боломжтой).

Хоёр дахь хувилбарт зориулж, ялангуяа API-ийн том хариуны агуулгыг багасгахыг хүсье. Бид юу хэлэхээ мэдэхгүй байна, гэхдээ бид шахсан хэлбэрээр нөөцлөгдсөн байх ёстой. Эхлээд бид өгөгдөл гэж юу болохыг мэдэх хэрэгтэй. Хоёрдугаарт, өгөгдөл ямар байх нь бидэнд хамаагүй. Semalt эдгээр сонголтуудыг судлах .

Унших файлууд, Мөрөөр шугам

Файлуудтай ажиллах олон функцууд байдаг. Semalt нь цөөн хэдэн гэнэн файл уншигддаг:

     // санахаас. phpфункцийн форматБи ($ байт, $ нарийн = 2) {$ units = array ("b", "kb", "mb", "gb", "tb");$ байт = хамгийн их ($ байт, 0);$ pow = давхрага (($ байт? лог ($ байт): 0) / log (1024));$ pow = min ($ pow, count ($ нэгж) - 1);$ байт / = (1 << (10 * $ pow));эргэх тойрог ($ байт, $ нарийвчлал). "". $ units [$ pow];}хэвлэх хэлбэрБит (санах ой_get_peak_usage   );    
     // унших-файл-шугам-by-line-1. phpфункц уншихTheFile ($ path) {$ lines = [];$ handle = fopen ($ path, "r");(! feof ($ handle)) {$ мөр [] = trim (fgets ($ handle));}fclose ($ бариул);буцааж $ мөрүүд;}readTheFile ("shakespeare .txt");"санах ойн. php" шаарддаг;    

Шекспирийн иж бүрэн бүтээл агуулсан текст файлыг уншиж байна. Текст файл нь ойролцоогоор 5. 5MB , оргил санах ойн хэрэглээ нь 12. 8MB . Одоо, нэг генераторыг ашиглан мөр бүрийг унших хэрэгтэй:

     // унших-файл-шугам-by-line-2. phpфункц уншихTheFile ($ path) {$ handle = fopen ($ path, "r");(! feof ($ handle)) {ургацтай обуд (fgets ($ бариул));}fclose ($ бариул);}readTheFile ("shakespeare .txt");"санах ойн. php" шаарддаг;    

Текст файл нь ижил хэмжээтэй боловч дээд санах ойн хэрэглээ нь 393KB юм. Энэ нь бидний уншиж байгаа өгөгдөлтэй ямар нэгэн зүйл хийх хүртэл юу ч биш гэсэн үг юм. Магадгүй бид хоёр хоосон мөрийг харах бүртээ баримтыг хувааж болно. Үүнтэй адил зүйл:

     // унших-файл-шугам-by-line-3. php$ iterator = readTheFile ("shakespeare .txt");$ buffer = "";foreach ($ iterator as $ давталт) {preg_match ("/ \ n {3} /", $ буфер, $ таарах);хэрэв (тоо ($ таарах)) {хэвлэх ".";$ buffer = "";} else {$ буфер. = $ давталт. PHP_EOL;}}"санах ойн. php" шаарддаг;    

Одоо бид хичнээн ой санамжаа хэчнээн санаж байна вэ? 1,216 хэсгүүдэд хуваахын зэрэгцээ бид зөвхөн 459KB санах ойг хэрэглэснийг мэдээд гайхаж байна уу? Генераторын шинж чанараас харахад хамгийн их санах ой нь давталтын хамгийн том текстийн хэсгийг хадгалах хэрэгтэй болно. Энэ тохиолдолд том хэсгүүд нь 101,985 тэмдэгтүүд юм.

Би генераторууд болон Никита Поповын Семаль номын сангуудын гүйцэтгэлийн өсөлтийг аль хэдийн бичсэн байгаа тул та илүү ихийг харахыг хүсч байгаа эсэхийг шалгаарай!

Семаль нь бусад хэрэглээтэй байдаг боловч энэ нь том хэмжээний файлуудыг унших чадвартай байдаг. Хэрэв бид өгөгдөл дээр ажиллах шаардлагатай бол генераторууд нь хамгийн сайн арга байж болох юм.

Файлуудын хооронд хоолой

Өгөгдөл дээр ажиллах шаардлагагүй тохиолдолд бид файлын датаг нэг файлаас нөгөөд шилжүүлэх боломжтой. Үүнийг хоолой гэж нэрлэдэг (магадгүй энэ нь тунгалаг биш л бол хоолойны дотор юу байгааг хардаггүй). Үүнийг урсгалын аргуудыг ашиглан хийж болно. Эхлээд нэг файлаас нөгөө рүү шилжүүлэх скрипт бичиж өгөөд, санах ойн хэрэглээг хэмжиж болох юм:

     // хоолойн файлуудаас 1. phpфайлын_put_contents ("piping-files-1 txt", file_get_contents ("shakespeare .txt"));"санах ойн. php" шаарддаг;    

Энэ скрипт нь текст файлаас хуулж ажиллуулахад санах ойн хэмжээ арай илүү ашигладаг. Semalt нь файлын агуулгыг шинэ файлд бичиж дуустал хадгалж байх ёстой. Жижиг файлуудын хувьд энэ нь зүгээр байж болно. Том файлуудыг ашиглаж эхлэх үед тийм ч их .

Нэг файлын хуулбарыг дамжуулах (эсвэл дамжуулах):

     // хоолойн файлуудаас 2. txt "," r ");$ handle2 = fopen ("piping-files-2 .txt", "w");stream_copy_to_stream ($ handle1, $ handle2);fclose ($ handle1);fclose ($ handle2);"санах ойн. php" шаарддаг;    

Энэ код бага зэрэг хачин юм. Бид хоёр файлыг хоёуланг нь зохицуулах, эхний уншигдах горим, хоёр дахь бичих горимд ажиллах боломжтой. Дараа нь бид эхнийхийгээс хоёр дахь нь хүртэл хуулж авдаг. Бид хоёулаа хоёуланг нь дахин хааж дуусаад дуусна. Ашигласан санах ой нь 393KB гэдгийг мэдээд гайхах болно.

Энэ бол мэддэг зүйл. Генераторын кодыг мөр бүрт уншихад ашигладаг зүйл биш гэж үү? Учир нь fgets гэсэн хоёр дахь аргумент нь мөр бүрт хичнээн байтыг уншихыг заана (анхдагч мөрөнд -1 өгөгдөнө.

stream_copy_to_stream -д гурав дахь аргумент нь яг ижил төрлийн параметртэй ижилхэн байна. stream_copy_to_stream нь нэг урсгалаас, нэг мөрөнд нэг мөрөнд уншиж, нөгөө рүү дамжуулдаг. Энэ нь үнэ цэнэтэй ажиллах шаардлагагүй тул генератор үнэ цэнийг бий болгодог.

Энэ текстийг дамжуулах нь бидэнд ач холбогдолтой биш юм. Тиймээс бусад жишээг авч үзье. Бид өөрсдийн CDN-ээс гаргасан зураглалыг дахин чиглүүлэх аппликешн чиглүүлэхийг хүссэн. Үүнийг дараах байдлаар дүрсэлж болно:

     // хоолойн файлуудаас 3. phpфайлын_put_contents ("piping-files-3 jpeg", file_get_contents ("https: // github com / assertchris / uploads / raw / master / rick jpg"));// эсвэл санах ойд мэдээлэл шаардлагагүй бол шууд үүнийг stdout уруу бичих хэрэгтэй"санах ойн. php" шаарддаг;    

Хэрэглээний маршрутыг бид энэ кодонд авчирсан. Харин локал файлын системээс файл ажиллуулахын оронд бид үүнийг CDN-ээс авмаар байна. Бид 38 file_get_contents -ийг илүү гоёмсог (Guzzle гэх мэт) -ээр орлуулж болох боловч бүрхүүлийн доор адилхан.

Санах ойн ашиглалт (энэ зурганд) нь ойролцоогоор 581KB . Одоо бид үүнийг хэрхэн дамжуулах вэ?

     // хоолойн файлуудаас 4. php$ handle1 = fopen ("https: // github com / assertchris / uploads / raw / master / rick jpg", "r");$ handle2 = fopen ("piping-files-4 jpeg", "w");// эсвэл санах ойд мэдээлэл шаардлагагүй бол шууд үүнийг stdout уруу бичих хэрэгтэйstream_copy_to_stream ($ handle1, $ handle2);fclose ($ handle1);fclose ($ handle2);"санах ойн. php" шаарддаг;    

Санах ойн хэрэглээ бага зэрэг багассан ( 400KB ) боловч үр дүн нь адил юм. Хэрэв бидэнд санах ойн мэдээлэл хэрэггүй байсан бол стандарт гаралтыг хэвлэж чадна. Үнэндээ PHP нь үүнийг хийх энгийн арга юм:

     $ handle1 = fopen ("https: // github com / assertchris / uploads / raw / master / rick jpg", "r");$ handle2 = fopen ("php: // stdout", "w");stream_copy_to_stream ($ handle1, $ handle2);fclose ($ handle1);fclose ($ handle2);// "санах ойн. php" шаарддаг;    

Бусад урсгалууд

Семаль гэдэг нь бидний хоолойноос өөр хоолойгоор дамжуулж, бичиж, уншиж болно:

  • php: // stdin (зөвхөн уншигдах)
  • php: // stderr (зөвхөн бичсэн, php: // stdout гэх мэт)
  • php: // input (зөвхөн уншигдах) нь бидэнд түүхий хүсэлт үүсгэх
  • php: // output (зөвхөн бичсэн) байгаа бөгөөд энэ нь бид гаралтын буферт
  • php: // memory ба php: // temp (read-write) бид өгөгдлүүдийг түр зуур хадгалах боломжтой газрууд юм. Өөрчлөлт нь php: // temp файлын систем дэх өгөгдлийг хангалттай том болоход хадгалах бөгөөд харин php: // memory нь дуусах хүртэл санах ойд хадгалагдах болно .

Шүүлтүүрүүд

Бидний шүүлтүүр гэгддэг өөр нэг заль мэх байдаг. Тэдгээр нь бидэн рүү нүүлгэхгүйгээр дамжуулалтын өгөгдөлд бага зэрэг хяналт тавьдаг алхам юм. Бидний shakespeare-ийг шахахыг хүссэн гэж төсөөлөөд үз дээ. txt . php$ zip = new ZipArchive ;$ filename = "filters-1 .zip";$ zip-> open ($ filename, ZipArchive :: CREATE);$ zip-> addFromString ("shakespeare .txt", file_get_contents ("shakespeare .txt"));$ zip-> close ;"санах ойн. php" шаарддаг;

Энэ бол маш нарийн код юм. Гэхдээ энэ нь цаг хугацааны хувьд 10. 75MB байдаг. Шүүлтүүрийн хувьд бид илүү сайн хийж чадна:

     // шүүлтүүрүүдээс-2. php$ handle1 = fopen ("php: // filter / zlib deflate / resource = shakespeare.txt", "r");$ handle2 = fopen ("шүүлтүүрүүд-2" индексжүүлсэн "," w ");stream_copy_to_stream ($ handle1, $ handle2);fclose ($ handle1);fclose ($ handle2);"санах ойн. php" шаарддаг;    

Энд бид php: // filter / zlib -г харж болно. deflate шүүлтүүр нь нөөцийн агуулгыг уншиж, шахдаг. Дараа нь бид энэ шахсан өгөгдлийг өөр файл руу хоолойгоор оруулж чадна. Энэ нь зөвхөн 896KB -ийг ашигладаг.

Энэ нь ижил форматтай биш, эсвэл зип архивлахад upsides байна гэдгийг би мэднэ. Хэрэв та өөр өөр форматыг сонгож, санах ойг 12 дахин хэмнэж чадвал чи гайхах хэрэгтэй.

Өгөгдлийг задлахын тулд бид задлагч файлыг өөр zlib шүүлтүүрээр дамжуулан ажиллуулж болно:

     // шүүлтүүрүүдээс-2. phpfile_get_contents ("php: // filter / zlib inflate / resource = filters-2" индексжүүлсэн ");    

"РС дэх урсгалыг ойлгох нь", "PHP Stream Semalt" ашиглахад голчлон хамрагдсан. Хэрэв та өөр өнцгөөс харахыг хүсч байвал, тэдгээрийг шалгаарай!

Шууд урсгалыг өөрчлөх

fopen болон file_get_contents өөрсдийн үндсэн багцын сонголттой байдаг боловч эдгээр нь бүрэн тохируулагдсан байдаг. Эдгээрийг тодорхойлохын тулд бид шинэ урсгал орчинг бий болгох хэрэгтэй:

     // үүсгэх-contexts-1. php$ өгөгдөл = join ("&", ["twitter = assertchris",]);$ headers = join ("\ r \ n", ["Агуулгын төрөл: application / x-www-form-urlencoded","Агуулга-урт:". strlen ($ өгөгдөл),]);$ options = ["http" => ["method" => "POST","толгой" => $ толгой хуудас,"агуулга" => $ өгөгдөл,],];$ context = stream_content_create ($ сонголтууд);$ handle = fopen ("https: // example.com / register", "r", false, $ context);$ хариу = stream_get_contents ($ бариул);fclose ($ бариул);    

Энэ жишээн дээр API POST хүсэлтийг хийхийг оролдож байна. API төгсгөлийн цэг нь аюулгүй байна, гэхдээ бид http контекстийн өмчийг http ба https -д ашигладаг шиг ашиглаарай. Бид хэд хэдэн толгой файлыг тавьж файлын бариулыг API рүү нээж өгнө. Уг контентыг бичвэрт анхаарал тавьдаг тул бариулыг зөвхөн унших боломжтой.

Семаль нь бидний хийж болох зүйлсийн ачаалал юм. Хэрэв та илүү ихийг мэдэхийг хүсвэл баримтыг үзэх нь зүйтэй юм.

Гаалийн протокол болон шүүлтүүр хийх

Бид бүгдийг боож өгдөг, заншлын протокол хийх талаар ярилцъя. Хийх ёстой маш олон ажлыг хийдэг. Гэхдээ энэ ажлыг хийж дуусмагц бидний урсгалыг хялбархан бүртгэх боломжтой: 13)

     хэрэв (in_array ("онцлох-нэрүүд", stream_get_wrappers   )) {stream_wrapper_unregister ("онцлох нэрс");}stream_wrapper_register ("highlight-names", "HighlightNamesProtocol");$ highlighted = file_get_contents ("highlight-names: // story txt");    

Semalt, мөн өөрчлөн урсгал шүүлтүүрийг бий болгох боломжтой. Баримт бичиг нь жишээ шүүлтүүртэй байна:

     Шүүлтүүр {нийтийн $ filtername;нийтийн $ paramspublic int шүүлтүүр (нөөцийн $ in, нөөц $ out, int & $ хэрэглэсэн,$ хаалтын үеэр)олон нийтийн хүчин төгөлдөр бус хязгаарлалт (invalid)олон нийтийн bool onCreate (хүчингүй)}    

Үүнийг амархан бүртгүүлж болно:

     $ handle = fopen ("түүх .txt", "w +");stream_filter_append ($ бариул, "онцлох нэрс", STREAM_FILTER_READ);    

highlight-names шинэ шүүлтүүр классын файлын нэр -тай таарах хэрэгтэй. Мөн шүүлтүүрийг php: // filter / highligh-names / resource = story -д ашиглах боломжтой. txt тэмдэгт мөр. Протоколыг тодорхойлохын тулд шүүлтүүрийг тодорхойлох нь илүү хялбар байдаг. Үүний нэг шалтгаан нь протоколууд нь директорын үйлдлийг зохицуулах шаардлагатай байдаг бол шүүлтүүрүүд нь зөвхөн өгөгдлийн хэсэг бүрийг зохицуулах шаардлагатай болдог.

Хэрэв та хэрэглэж байгаа бол өөрчлөн тохируулсан протоколууд болон шүүлтүүрүүдийг үүсгэхийг туршиж үзэхийг танаас хүсч байна. Хэрэв та шүүлтүүрийг stream_copy_to_stream үйлдлүүдэд ашиглах боломжтой бол таны програмууд нь буруу файлтай ажиллах үед санах ой байхгүйгээр ашиглах болно. Шүүгдсэн шифрлэх-зураг шүүлтүүр буюу шифрлэх-програм шүүлтүүрийг бичихийг төсөөл.

Дүгнэлт

Энэ нь бидний байнга зовж байдаг асуудал биш, их хэмжээний файлуудтай ажиллахад эвгүй байдалд ороход амархан байдаг. Асинхрон хэрэглээнд, бид санах ойн ашиглалтанд анхаарал тавихаас болгоомжилж байхад бүхэл серверийг доош нь оруулахад хялбар байдаг.

Энэхүү гарын авлага нь таныг хэд хэдэн шинэ санаануудыг танилцуулсан (эсвэл тэдгээрийн талаархи санах ойг дахин сэргээж), ингэснээр та том файлуудыг хэрхэн уншиж, бичих талаар илүү ихийг бодох болно. Бид урсгал болон генератортой танилцаж, функцийг ашиглахаа болих (file_get_contents : бүх алдааны категориуд бидний програмууд алга болно. Энэ нь зорилгодоо хүрэх сайхан зүйл мэт санагдаж байна!

March 1, 2018