14/01/2019, 22:54

[C#] Hướng dẫn sử dụng Parallel Download trong lập trình csharp

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách sử dụng Parallel Download Website trong lập trình C#. Trong ví dụ này, mình sẽ tải dữ liệu của 10 website và khi tải source code về xong mình sẽ count số dòng code của từng website. Bình ...

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách sử dụng Parallel Download Website trong lập trình C#.

Trong ví dụ này, mình sẽ tải dữ liệu của 10 website và khi tải source code về xong mình sẽ count số dòng code của từng website.

Bình thường nếu các bạn tải đồng bộ (Sync) dữ liệu từ 10 website thì tốc độ tải chậm vì tải đồng bộ, và GUI của Form sẽ bị treo, các bạn sẽ không thể thao tác được.

Cách tải dữ liệu bằng Parallel nó sẽ tải dữ liệu bất đồng bộ (Async) từng website (một lần tải nhiều website cùng một lúc, và nó không làm treo form của mình).

Ví dụ: Mình có 10 website như sau.

public static List<string> PrepData()
{
      List<string> output = new List<string>();

      output.Add("https://laptrinhvb.net");
      output.Add("https://code24h.com");
      output.Add("https://howteam.vn");
      output.Add("https://vnexpress.net");
      output.Add("https://24h.com.vn");
      output.Add("https://dantri.com.vn");
      output.Add("https://genk.vn");
      output.Add("https://bongdaso.com");
      output.Add("https://quantrimang.com");
      output.Add("https://noithattuonglai.com.vn");

      return output;
}      

Giao diện download bằng Paravell có ProcessBar C#:

parallel_download_csharp

Như hình demo trên, các bạn thấy tốc độ tải dữ liệu của 10 website trên chỉ mất chưa đến 2 giây là đã hoàn tất.

Đầu tiên các bạn cần tạo một Model Class với tên WebsiteDataModel.cs

Class này chứa 2 thuộc tính: WebsiteURL và WebsiteData

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ParallellDownload
{
    class WebsiteDataModel
    {
        public string WebsiteUrl { get; set; } = "";
        public string WebsiteData { get; set; } = "";
    }
}

Tiếp đến, các bạn tạo tiếp cho mình một class ProgressReportModel.cs

Class này sử dụng để hiển thị phần trăm progessbar đã tải dữ liệu về.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ParallellDownload
{
    class ProgressReportModel
    {
        public int PercentageComplete { get; set; } = 0;
        public List<WebsiteDataModel> SitesDownloaded { get; set; } = new List<WebsiteDataModel>();
    }
}

Tiếp theo, các bạn tạo tiếp một class với tên DemoMethod.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ParallellDownload
{
    static class DownloadMethods
    {
        public static List<string> PrepData()
        {
            List<string> output = new List<string>();

            output.Add("https://laptrinhvb.net");
            output.Add("https://code24h.com");
            output.Add("https://howkteam.vn");
            output.Add("https://vnexpress.net");
            output.Add("https://24h.com.vn");
            output.Add("https://dantri.com.vn");
            output.Add("https://genk.vn");
            output.Add("http://bongdaso.com");
            output.Add("https://quantrimang.com");
            output.Add("https://noithattuonglai.com.vn");

            return output;
        }      

        public static async Task<List<WebsiteDataModel>> RunDownloadParallelAsyncV2(IProgress<ProgressReportModel> progress, CancellationTokenSource cts)
        {
            List<string> websites = PrepData();
            List<WebsiteDataModel> output = new List<WebsiteDataModel>();
            ProgressReportModel report = new ProgressReportModel();          
            ParallelOptions po = new ParallelOptions();
            po.MaxDegreeOfParallelism = 8;
            po.CancellationToken = cts.Token;

            await Task.Run(() =>
            {
                try
                {
                    Parallel.ForEach<string>(websites, po,   (site) =>
                    {                       
                        WebsiteDataModel results =  DownloadWebsite(site);
                        output.Add(results);

                        report.SitesDownloaded = output;
                        report.PercentageComplete = (output.Count * 100) / websites.Count;
                        progress.Report(report);
                        po.CancellationToken.ThrowIfCancellationRequested();
                    });
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine(e.Message);
                }
                finally
                {
                    //cts.Dispose();
                }

                
            });

            return output;
        }
        private static WebsiteDataModel DownloadWebsite(string websiteURL)
        {
            WebsiteDataModel output = new WebsiteDataModel();
            WebClient client = new WebClient();

            output.WebsiteUrl = websiteURL;
            output.WebsiteData = client.DownloadString(websiteURL);

            return output;
        }
    }
}

Và tiếp theo là viết hàm cho nút Download Parallel và nút dừng tải thông qua sử dụng Token.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ParallellDownload
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        CancellationTokenSource cts;


        private void PrintResults(List<WebsiteDataModel> results)
        {
            rtf_result.Text = "";
            foreach (var item in results)
            {
                rtf_result.Text += $"{ item.WebsiteUrl } downloaded: { item.WebsiteData.Length } characters long.{ Environment.NewLine }";
            }
        }

        private void ReportProgress(object sender, ProgressReportModel e)
        {
            progressBar.Value = e.PercentageComplete;
            lbl_percent.Text = e.PercentageComplete.ToString() + "%";
            PrintResults(e.SitesDownloaded);
        }

        private async void btn_download_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            Progress<ProgressReportModel> progress = new Progress<ProgressReportModel>();
            progress.ProgressChanged += ReportProgress;

            var watch = System.Diagnostics.Stopwatch.StartNew();

            var results = await DownloadMethods.RunDownloadParallelAsyncV2(progress, cts);
            PrintResults(results);

            watch.Stop();
            var elapsedMs = watch.ElapsedMilliseconds;

            rtf_result.Text += $"Total execution time: { elapsedMs }";
        }

        private void btn_stop_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }



     
    }
}

Hy vọng bài viết sẽ giúp ích được cho các bạn về cách sử dụng bất đồng bộ trong C#.

Thanks For Watching!

DOWNLOAD SOURCE

Tags: async c#await and async c#parallel download c#httprequest
0