PDA

View Full Version : خواندن 900000 هزار صفحه



بیتا حکمت
جمعه 09 مرداد 1394, 23:32 عصر
سلام ، اگر به ساختار لینک های سایت stackoverflow دقت کنین ، می بنید که قسمت اول ادرس یک رشته اس و قسمت دوم یک عدد 6 رقمی ، مثلا

قسمت اول لینک (یک رشته ثابت ):



http://stackoverflow.com/questions/





قسمت دوم که یک عدد هست




/31753779






http://stackoverflow.com/questions/31753779




البته ممکنه همه لینک ها چنین ساختاری نداشته باشن اما مهم نیست فقط میخوام یاد بگیرم که با استفاده از نرد محتویات 900000 صفحه رو چطوری در سریعترین زمان
ممکن بخونم و ..

__

من برای بررسی اینکه در بازه (اولین عدد 6 رقمی ) تا (اخرین عدد 6 رقمی ) لینک چه محتوایی داره ، از کد زیر استفاده کردم :




int shomarand = 0;
public void search()
{
this.Invoke((MethodInvoker)delegate() { this.progressBar1.Maximum = 999999; });

for (int i = 999999; i >= 100000; i--)
{
// label1.Text = "http://stackoverflow.com/questions/" + i.ToString();
try
{

// writeclearlik(rs.GetXHtmlFromUri(line).ToString(), line);
// label1.Text = line;
WebClient client = new WebClient();
var data = client.DownloadData("http://stackoverflow.com/questions/" + i.ToString() + "/");
var html = Encoding.UTF8.GetString(data);
if (html.ToString().Contains("Page Not Found"))
{
using (StreamWriter w = File.AppendText("clearlink.txt"))
{

w.WriteLine(shomarand.ToString() + "- " + "http://stackoverflow.com/questions/" + i.ToString() + "/", Encoding.UTF8);

shomarand++;
}
}


using (StreamWriter w = File.AppendText("cheaked.txt"))
{

w.WriteLine(System.DateTime.Now.ToString() + "-" + "http://stackoverflow.com/questions/" + i.ToString() + "/", Encoding.UTF8);


}
}
catch
{



}

this.Invoke((MethodInvoker)delegate() { progressBar1.Value++; });


}
MessageBox.Show("تمام شد ");






کد باتن برای شروع پروسس :



if (!System.IO.File.Exists("cheaked.txt"))
System.IO.File.Create("cheaked.txt");





if (System.IO.File.Exists("clearlink.txt"))

File.Delete("clearlink.txt");
System.IO.File.Create("clearlink.txt");


Thread t = new Thread(search); // Kick off a new thread
t.Start();





حالا

سوال اول : ساعتها طول می کشه تا این 900000 صفحه بررسی بشن ، برای اینکه از لحاظ زمانی سرعت اجرای برنامه و بررسی صفحات بیشتر بشه ، باید چه کنیم ؟

سوال دوم : چرا کد پایین درون متد Search باعث بروز خطا میشه ، من میخوام تو خروجی لحظه به لحظه مشخص باشه که کدوم آدرس اینترنتی در حال بررسی است ..



label1.Text = "http://stackoverflow.com/questions/" + i.ToString();



سوال سوم : حتی با وجود دقایق زیادی از اجرای برنامه ، پروسس بار تغییری نمی کنه .. در حالی که باید در حال پر شدن نشون داده می شد

aliagamon
شنبه 10 مرداد 1394, 01:37 صبح
برای سوال اول یک راه کار هست اما بخش عمده ای از بازدهی اون مربوط به سرعت اینترنتتون هست
شما باید کارتون رو خورد کنید و چند ترد موازی با متغییر فراخوانی کنید
یعنی اینکه یک ترد 100000 تا 200000 رو بگرده بعدی 200001 تا 300000 بعدی 300001 تا ....
اینطوری کار 10 برابر سریع تر انجام خواهد شد ( همون طور که گفتم به اینترنتتون هم ربط داره که چند ترد همزمان رو جواب بده)
سوال دوم شما نمیتونید از داخل یک ترد در اعضای ترد دیگر تعییر ایجاد کنید پس باید اینطوری عمل کنید:

this.Invoke((MethodInvoker)delegate() { this.label1.Text = "http://stackoverflow.com/questions/" + i.ToString(); });

سوال سوم : روشتون یکم بده برای اینکار یک ایرادی که اول از همه معلومه اینه که شما ماکسیمم رو 9999999 قرار دادید اما value فعلی 0 هست که استباهه با این روش کاری value هم باید بکنید 100000 که کلا کار غلطه چون از شروع کار 10 % کار رو تموم شده نشون میده شما ماکسیمم رو 899999 قرار بدید در کل با بریک پوینت مرجله به مرجله برنامه رو دنبال کنید ببینید کجای کار میلنگه شاید واقعا سرعت کار اونقدر کنده که پیشرفتی نمیبینین شما میتونید یک lable بزارید و هرجا progressbar رو +1 کردید مقدار اون lable هم اضافه کنید که مطمعن بشید از کارکرد برنامه

ژیار رحیمی
شنبه 10 مرداد 1394, 04:30 صبح
دوست گرامی به تشخیص بنده سایت استک اورفلو بر اساس تکنولوژی MVC هست .(
900000 صفحه
) نیست
900000 رکورد هست در مدل MVC ممکنه بر اساس نیاز چندین View داشته باشی اینم حداکثر از 10 تا 15 تا View اونم بر اساس نیاز خروجی سایت هست. شما با رکورد سروکار داری نه با صفحه.جستجو در تعداد رکوردهای بالا مثلا همین عدد 900000 رکورد روی سرورهای قدرتمند مثل اینه که شما روی سیستم خانگی حلقه for 1 تا 10 رو اجرا کنی

اما
سوال دوم : چرا
کد پایین درون متد Search باعث بروز خطا میشه ، من میخوام تو خروجی لحظه به لحظه مشخص باشه که کدوم آدرس اینترنتی در حال بررسی است
شما در کدتون کار خاصی رو انجام نمیدین اگرم درست اجرا بشه شما فقط داری آدرس صفحات رو تولید میکنی هیچ نوع خروجی به شما از طرف سایت نمیدهد.شما بعنوان کاربر وقتی دسترسی به سرور و admin سایتی نداری نمیتونی گزارشاتی از قبیل اینکه درحال حاضر در سرور چه اتفاقاتی در شرف جریان یا در حال پردازش هست داشته باشی.

بیتا حکمت
شنبه 10 مرداد 1394, 05:16 صبح
اما
سوال دوم : چرا
کد پایین درون متد Search باعث بروز خطا میشه ، من میخوام تو خروجی لحظه به لحظه مشخص باشه که کدوم آدرس اینترنتی در حال بررسی است
شما در کدتون کار خاصی رو انجام نمیدین اگرم درست اجرا بشه شما فقط داری آدرس صفحات رو تولید میکنی هیچ نوع خروجی به شما از طرف سایت نمیدهد.شما بعنوان کاربر وقتی دسترسی به سرور و admin سایتی نداری نمیتونی گزارشاتی از قبیل اینکه درحال حاضر در سرور چه اتفاقاتی در شرف جریان یا در حال پردازش هست داشته باشی.

بابت راهنمایی ها و وقتی که گذاشتین بی نهایت ممنونم
از اقای از شما و جناب aliagamon (http://barnamenevis.org/member.php?214213-aliagamon)@ هم تشکر می کنم ..
الان متوجه اشتباهاتم شدم ، فقط میخوام اینو بدونم به فرض که ادرس های داده شده به لینک اگر صحیح بود برای اجرای همزمان ترد باید بعد تعریف تردها
به این صورت عمل می کردم ؟!




Thread t1 = new Thread(search1);
t1.Start();

Thread t2 = new Thread(search2);
t2.Start();



البته اینطورها هم نیست که هیچ فیدبکی از طرف صفحات ساخته شده دریاقت نمیشه ، شایدم من منظور شما رو خوب متوجه نشدم ، هر چند که این لینک های تولید شده در سایت stackoverflow به صورت واقعی وجود ندارن ، اما سورس Html ی که از این لینک های ساخته شده دریافت میشه بدست میاد با هم فرق دارن ..




string ht=null;
try
{

// writeclearlik(rs.GetXHtmlFromUri(line).ToString(), line);
// label1.Text = line;
WebClient client = new WebClient();
var data = client.DownloadData("http://stackoverflow.com/questions/999999/");
var html = Encoding.UTF8.GetString(data);
ht = html.ToString();
if (html.ToString().Contains("filemerge"))
{
MessageBox.Show("پیدا شد ");

}



}
catch
{



}




اگر به جای 999999 به 999998 وارد کنین (تغییر لینک منظورمه ) می بنید که خروجی فرق کرده ..
پ ن : منم موافقم که این روش مناسب خزش در یک سایت نیست ، هدفم از ایجاد تاپیک درک بیشتر از تردها در قالب مثال و موضوعی هست
که برام جالبه

ژیار رحیمی
شنبه 10 مرداد 1394, 05:40 صبح
شما وقتی بخوای آدرسی از سایتی دیگر رو چک بکنی که درست هست یا نه باید درخواست(آدرس تولید شده) رو بفرستی به سرور اگر پاسخی از سرور دریافت کردی بعد اقدام به انجام کار بعدی بکنی.دو نمونه کد میزارم برای چک کردن لینک فرستاده شده به سرور که آیا وجود دارد یا نه


using System.Net;


///
/// Checks the file exists or not.
///
/// The URL of the remote file.
/// True : If the file exits, False if file not exists
private bool RemoteFileExists(string url)
{
try
{
//Creating the HttpWebRequest
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
//Setting the Request method HEAD, you can also use GET too.
request.Method = "HEAD";
//Getting the Web Response.
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//Returns TRUE if the Status code == 200
return (response.StatusCode == HttpStatusCode.OK);
}
catch
{
//Any exception will returns false.
return false;
}
}


نمونه کد بعدی



// using MyClient from linked post
using(var client = new MyClient()) {
client.HeadOnly = true;
// fine, no content downloaded
string s1 = client.DownloadString("http://google.com");
// throws 404
string s2 = client.DownloadString("http://google.com/silly");




شما برای چک کردن رنج اعداد بستگی به بازه جستجو میتونی چندین Thread یا Task تولید وهر Thread کارش چک کردن یه بخش از اعداد باشه و هر Thread آرایه ای از اعداد Valid رو برگردونه.میتونی تابع اول رو داخل Thread و حلقه for برای شمارش بازه اعداد بزاری به نتیجه دلخواه میرسی


خانم حکمت کدی که شما برای چک کردن گذاشتی کد html صفخات رو بررسی میکند.لازم به یاد آوری هست که حتی صفحاتی که پیام خطای 404 نمایش میدن دارای کد html هستن جهت نمایش به کاربر شما باید Header صفحه رو چک کنی که اونم با تابع اول که گذاشتم قابل بررسی هست

hamid_hr
شنبه 10 مرداد 1394, 09:19 صبح
بنظر من شما بهتره از parallel.for استفاده کنی
به این صورت

اول یه تابع مینویسین که اطلاعات صفحه رو دانلود کنه و ذخیره کنه و......
اون تابعو با thread فراخونی میکنی
توی تابع میای از این نوع for استفاده میکنی
Parallel.For(100000, 999999, i => {
//کدهای شما
});

بیتا حکمت
شنبه 10 مرداد 1394, 10:41 صبح
بنظر من شما بهتره از parallel.for استفاده کنی
به این صورت

اول یه تابع مینویسین که اطلاعات صفحه رو دانلود کنه و ذخیره کنه و......
اون تابعو با thread فراخونی میکنی
توی تابع میای از این نوع for استفاده میکنی
Parallel.For(100000, 999999, i => {
//کدهای شما
});

ممنون ، خیلی جالب بود

برای اینکه تابعی بنویسم که سورس صفحه رو دانلود کنه خوب مسلما" این تابع باید یه پارامتر ورودی داشته باشه تا لینک رو براش ارسال کنم
ولی ترد متدهایی رو قبول می کنه که ورودی ندارن (( تا جایی که خوندم اگر اشتباه نکرده باشم ، متدها دارای پارامتر رو نمیشه به ترد ارسال کرد ))

این قسمت که کامنت زدین // کدهای شما ، در واقع منظورتون اینکه T.start رو اونجا بنویسم ؟!

ژیار رحیمی
شنبه 10 مرداد 1394, 11:35 صبح
نه در بخش (کد شما// تابع یا دستورات چک کردن url) رو قرار بدین.Parallel.For احتیاجی به استارت نداره مثل حلقه For معمولی اجرا ولی با این تفاوت که خودش بازه حلقه رو به چندین قسمت تقسیم و هر قسمت رو با یه Thread مجزا بصورت همزمان Parallel انجام میدهد

hamid_hr
شنبه 10 مرداد 1394, 11:40 صبح
ولی ترد متدهایی رو قبول می کنه که ورودی ندارن
نه اشتباهه
شما یه تابع بنویسین با ورودی object
بعد اینطوری بنویسین
t.start("....");

ورودی از نوع ابجکت میگیره