PDA

توجه ! این یک نسخه آرشیو شده میباشد و در این حالت شما عکسی را مشاهده نمیکنید برای مشاهده کامل متن و عکسها بر روی لینک مقابل کلیک کنید : چگونه یک کد php را روی یک فایل سنگین اجرا کنیم؟



سیدرضا بازیار
April 20th, 2018, 19:29
درود

من یه کد php دارم که یه فایل txt رو باز میکنه. سپس کلیه لاین هایی که .com توی اونا باشه رو حذف میکنه
مثلا اگه یه فایل حاوی کلی دامین باشه، دامنه هایی که .com هستند رو از فایل حذف میکنه



<?php
$fname = "test.txt";
$lines = file($fname);
foreach($lines as $line) if(!strstr($line, ".com")) $out .= $line;
$f = fopen($fname, "w");
fwrite($f, $out);
fclose($f);
?>

حالا وقتی این کد رو روی یه فایل سنگین که میلیون ها دامین توی اونه اجرا میکنم اجرا نمیشه!

راه حل این مشکل چیه؟

rayanagostar
April 20th, 2018, 19:39
خیلی منطقی تره ابتدا فایل رو واردsql بکنید ( داده هاشو )‌و بعد از طریق دیتابیس انجام بدید

سیدرضا بازیار
April 20th, 2018, 19:42
خیلی منطقی تره ابتدا فایل رو واردsql بکنید ( داده هاشو )‌و بعد از طریق دیتابیس انجام بدید

مشکل اینجاس که نمیخوام از طریق دیتابیس باشه
پروژه ای رو که میخوام پیاده کنم دیتابیس نباید داشته باشه...

T.Toosi
April 20th, 2018, 21:58
باسلام، اگر از file استفاده کنید با توجه به حجم فایل نیاز به مموری دارید، به طور مثال اگر فایل 500mb هست نیاز هست داخل PHP.INI محدودیت مموری را تنظیم کنید، اما اگر از fopen استفاده کنید چون اشاره گر هست اگر سیستم عامل 32 بیت است می توانید تا 2 گیگ فایل (به صورت stream) بارگذاری کنید، اگر بیشتر از 2 گیگ است باید سیستم عامل 64 بیت و PHP 7 استفاده کنید.


$lines = file($fname);

JeyServer
April 20th, 2018, 22:38
سلام
من با برنامه زیر یک فایل دیگه حاوی 21 میلیون آدرس دامنه (که تعداد دامنه com شانسی است)‌ ایجاد کردم.

<?php
$chars = implode("", array_merge(range('a', 'z'), range('A', 'Z'), range('0', '9')));
$tlds = array('com', 'net', 'org', 'ir');
$file = fopen('domains.txt', 'a');
for($x = 0; $x < 21000000;$x++) {
$length = rand(5,15);
$tld = $tlds[rand(0, count($tlds) - 1)];
$chars = str_shuffle($chars);
fwrite($file, substr($chars, 0, $length).'.'.$tld."\n");
}
fclose($file);


حجم فایل نهایتا 309.7 مگابایت شد.
با برنامه زیر آدرس های غیر com رو جدا کردم:

<?php
$source = fopen('domains.txt', 'r');
$dest = fopen("domains-filtered.txt", 'w');
while (($line = fgets($source, 128)) !== false) {
if (substr(rtrim($line), -4) != ".com") {
fwrite($dest, $line);
}
}
fclose($source);
fclose($dest);


این برنامه توی 44.97 ثانیه روی سیستم من اجرا شد و حجم فایل خروجی 231 مگابایت شد:

➜ Desktop /usr/bin/time -v php b.php
Command being timed: "php b.php"
User time (seconds): 12.17
System time (seconds): 32.01
Percent of CPU this job got: 98%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:44.97
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 29392
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 2015
Voluntary context switches: 4
Involuntary context switches: 1069
Swaps: 0
File system inputs: 8
File system outputs: 451232
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0


----------------------
هرچند که این سوال استاتر نبود اما برای خودم جالب بود که این بار همون فایل رو با یک زبان سطح پایینتر مقایسه کنم بنابراین من یکبار دیگه همون فایل قبلی رو با برنامه ی c پردازش کردم:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
char * line = NULL;
size_t len = 0;
ssize_t read;
char tld[5];

FILE * source = fopen("./domains.txt", "r");
if (source == NULL)
exit(EXIT_FAILURE);

FILE * dest = fopen("./domains-filtered.txt", "w");
if (dest == NULL)
exit(EXIT_FAILURE);

while ((read = getline(&line, &len, source)) != -1) {
memcpy( tld, &line[read - 5], 4);
tld[4] = '\0';
if (strcmp(tld, ".com")) {
fwrite(line, 1, read, dest);
}
}

fclose(source);
fclose(dest);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
این بار برنامه توی 2.61 ثانیه اجرا شد (حدودا 17 برابر سریعتر)

➜ Desktop /usr/bin/time -v ./a.out
Command being timed: "./a.out"
User time (seconds): 1.34
System time (seconds): 0.23
Percent of CPU this job got: 60%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.61
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 1244
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 64
Voluntary context switches: 6
Involuntary context switches: 114
Swaps: 0
File system inputs: 0
File system outputs: 451224
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

سیدرضا بازیار
April 22nd, 2018, 14:20
باسلام، اگر از file استفاده کنید با توجه به حجم فایل نیاز به مموری دارید، به طور مثال اگر فایل 500mb هست نیاز هست داخل PHP.INI محدودیت مموری را تنظیم کنید، اما اگر از fopen استفاده کنید چون اشاره گر هست اگر سیستم عامل 32 بیت است می توانید تا 2 گیگ فایل (به صورت stream) بارگذاری کنید، اگر بیشتر از 2 گیگ است باید سیستم عامل 64 بیت و PHP 7 استفاده کنید.


$lines = file($fname);

سیستم عامل من ۶۴ بیتی هست و php7 استفاده میکنم
الان توی php.ini باید چی بنویسم؟

- - - Updated - - -


سلام
من با برنامه زیر یک فایل دیگه حاوی 21 میلیون آدرس دامنه (که تعداد دامنه com شانسی است)‌ ایجاد کردم.

<?php
$chars = implode("", array_merge(range('a', 'z'), range('A', 'Z'), range('0', '9')));
$tlds = array('com', 'net', 'org', 'ir');
$file = fopen('domains.txt', 'a');
for($x = 0; $x < 21000000;$x++) {
$length = rand(5,15);
$tld = $tlds[rand(0, count($tlds) - 1)];
$chars = str_shuffle($chars);
fwrite($file, substr($chars, 0, $length).'.'.$tld."\n");
}
fclose($file);


حجم فایل نهایتا 309.7 مگابایت شد.
با برنامه زیر آدرس های غیر com رو جدا کردم:

<?php
$source = fopen('domains.txt', 'r');
$dest = fopen("domains-filtered.txt", 'w');
while (($line = fgets($source, 128)) !== false) {
if (substr(rtrim($line), -4) != ".com") {
fwrite($dest, $line);
}
}
fclose($source);
fclose($dest);


این برنامه توی 44.97 ثانیه روی سیستم من اجرا شد و حجم فایل خروجی 231 مگابایت شد:

➜ Desktop /usr/bin/time -v php b.php
Command being timed: "php b.php"
User time (seconds): 12.17
System time (seconds): 32.01
Percent of CPU this job got: 98%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:44.97
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 29392
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 2015
Voluntary context switches: 4
Involuntary context switches: 1069
Swaps: 0
File system inputs: 8
File system outputs: 451232
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0


----------------------
هرچند که این سوال استاتر نبود اما برای خودم جالب بود که این بار همون فایل رو با یک زبان سطح پایینتر مقایسه کنم بنابراین من یکبار دیگه همون فایل قبلی رو با برنامه ی c پردازش کردم:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
char * line = NULL;
size_t len = 0;
ssize_t read;
char tld[5];

FILE * source = fopen("./domains.txt", "r");
if (source == NULL)
exit(EXIT_FAILURE);

FILE * dest = fopen("./domains-filtered.txt", "w");
if (dest == NULL)
exit(EXIT_FAILURE);

while ((read = getline(&line, &len, source)) != -1) {
memcpy( tld, &line[read - 5], 4);
tld[4] = '\0';
if (strcmp(tld, ".com")) {
fwrite(line, 1, read, dest);
}
}

fclose(source);
fclose(dest);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
این بار برنامه توی 2.61 ثانیه اجرا شد (حدودا 17 برابر سریعتر)

➜ Desktop /usr/bin/time -v ./a.out
Command being timed: "./a.out"
User time (seconds): 1.34
System time (seconds): 0.23
Percent of CPU this job got: 60%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.61
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 1244
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 64
Voluntary context switches: 6
Involuntary context switches: 114
Swaps: 0
File system inputs: 0
File system outputs: 451224
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

کد شما به خوبی کار میکنه... چرا کد من کار نمیکرد؟

JeyServer
April 22nd, 2018, 14:26
الان اکه بخواید با همون کد فقط دامنه های .com رو جدا کنید چیکار میکنید؟ عمل میکنه؟
توی خط پنجم برنامه بالا،علامت تعجب (!) رو به (=) تبدیل کنید.
در نهایت:

<?php
$source = fopen('domains.txt', 'r');
$dest = fopen("domains-filtered.txt", 'w');
while (($line = fgets($source, 128)) !== false) {
if (substr(rtrim($line), -4) == ".com") {
fwrite($dest, $line);
}
}
fclose($source);
fclose($dest);

سیدرضا بازیار
April 22nd, 2018, 14:28
توی خط پنجم برنامه بالا،علامت تعجب (!) رو به (=) تبدیل کنید.
در نهایت:

<?php
$source = fopen('domains.txt', 'r');
$dest = fopen("domains-filtered.txt", 'w');
while (($line = fgets($source, 128)) !== false) {
if (substr(rtrim($line), -4) == ".com") {
fwrite($dest, $line);
}
}
fclose($source);
fclose($dest);


درسته. چون متوجه شدم ویرایش کردم...
فقط برام سواله که چرا کد من کار نکرد؟ مشکل کد من چی بود؟

JeyServer
April 22nd, 2018, 14:34
کد شما به خوبی کار میکنه... چرا کد من کار نمیکرد؟

چون شما از تابع file استفاده کرده بودید، این تابع ابتدا کل فایل رو بصورت خط به خط میخونه و هر خط رو در یک خونه آرایه ذخیره میکنه.
دراینصورت شما به حجم کل فایل رم استفاده میکنید چون کل فایل رو از روی هارد خوندید، خط به خط جدا کردید و روی RAM ذخیره کردید و این میتونه خیلی در بازدهی برنامه چالش برانگیز باشه.

من به جای file() از توابع fopen و fgets استفاده کردم. تابع fgets یک خط از فایل رو میخونه و بعد از اینکه کار شما با اون خط تموم شد، فراموشش میکنه و بنابراین دیگه مهم نیست که حجم فایل شما چقدر باشه، همیشه منابع اشغال شده در حداقل خواهند بود.

همینطور شما بعد از جداسازی خط های مورد نظر اون هارو در یک متغییر ذخیره میکردید، یعنی مجددا به اندازه حجم فایل خروجی رم استفاده میکردید، من به جای اینکه دامنه هارو ذخیره کنم تا در نهایت یکجا همه رو ذخیره کنم، هر خط رو در همون لحظه ذخیره میکردم در نتیجه RAM مشغول نمیشه!