استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

فرض کنید که داخل یک متد باید چندین متد را به صورت await فراخوانی کنید. به صورت عادی زمانی که متدها فراخوانی می شوند هر بخش await بعد از تکمیل await قبلی اجرا خواهد شد و مقادیر بازگشتی به صورت یکجا در اختیار شما قرار نمیگیرند. برای مثال، کد زیر را در نظر بگیرید:

private async void AsyncBtn_Click(object sender, EventArgs e)
{
    Result1TextBox.Text = (await Task1()).ToString();
    Result12extBox.Text = (await Task2()).ToString();
}
 
private Task < long > Task1()
{
    return Task.Run<long>(() = >
    {
        var num = Enumerable.Repeat(10, 1000);
        long sum = 0;
        foreach (var item in num)
        {
            System.Threading.Thread.Sleep(2);
            sum += item;
        }
        return sum;
    });
}
private Task < long > Task2()
{
    return Task.Run<long>(() = >
    {
        var num = Enumerable.Repeat(10, 1000);
        long sum = 0;
        foreach (var item in num)
        {
            System.Threading.Thread.Sleep(2);
            sum += item;
        }
        return sum;
    });
}

 

در کد بالا، ابتدا عملیات Task1 انجام شده و نتیجه نمایش داده می شود و پس از آن Task2 اجرا شده و نتیجه نمایش داده می شود. برای رفع وقفه بین اجرای دو Task از متد WhenAll استفاده می کنیم. برای استفاده از متد WhenAll کد BtnAsync_Click را به صورت زیر تغییر می دهیم:

 

private async void AsyncBtn_Click(object sender, EventArgs e)
{
    var results = await Task.WhenAll(Task1(), Task2());
    txtBox.Text = results[0].ToString();
    txtSecond.Text = results[1].ToString();
}

 

با ایجاد تغییر کد بالا، خروجی متد WhenAll یک آرایه از نوع long خواهد بود که هر یک از اندیس های آرایه به ترتیب خروجی متدهای اول و دوم می باشد و به صورت بالا می توان خروجی ها را در TextBox ها نمایش داد.

منبع


قسمت اول آموزش-برنامه نویسی Asynchronous – آشنایی با Process ها، Thread ها و AppDomain ها

قسمت دوم آموزش- آشنایی با ماهیت Asynchronous در Delegate ها

قسمت سوم آموزش-آشنایی با فضای نام System.Threading و کلاس Thread

قسمت چهارم آموزش- آشنایی با Thread های Foreground و Background در دات نت

قسمت پنجم آموزش- آشنایی با مشکل Concurrency در برنامه های Multi-Threaded و راهکار های رفع این مشکل

قسمت ششم آموزش- آشنایی با کلاس Timer در زبان سی شارپ

قسمت هفتم آموزش-آشنایی با CLR ThreadPool در دات نت

قسمت هشتم آموزش- مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

قسمت نهم آموزش- برنامه نویسی Parallel:آشنایی با کلاس Task در سی شارپ

قسمت دهم آموزش-برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

قسمت یازدهم آموزش- برنامه نویسی Parallel در سی شارپ :: کوئری های Parallel در LINQ

قسمت دوازدهم آموزش- آشنایی با کلمات کلیدی async و await در زبان سی شارپ

قسمت سیزدهم آموزش- استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

 

 

 

برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

زمانی که عملیاتی را به عنوان یک Task اجرا می کنیم، ممکن است بخواهیم آن Task را در حین اجرا متوقف کنیم، برای مثال، Task ای داریم که در حال پردازش 1000 فایل است و کاربر باید این امکان را داشته باشد که Task در حال اجرا را متوقف کند. عملیات متوقف کردن Task ها هم برای متدهای کلاس Parallel امکان پذیر است و هم کلاس Task. برای اینکار می بایست از کلاس CancellationToken استفاده کنیم. برای مثال Task زیر را در نظر بگیرید که حاصل میانگین جمع اعداد 1 تا 100 را محاسبه می کند:

Task < int > averageTask = new Task < int > (() =>
{
    Console.WriteLine("Calculating average...");
    Console.WriteLine("Press Ctrl+C to cancel...");
    var sum = 0;
    for (int counter = 1; counter < = 100; counter++)
    {
        sum += counter;
        Thread.Sleep(100);
    }
    Console.WriteLine("All done.");
    return sum/100;
});
averageTask.Start();
Console.WriteLine(averageTask.Result);

قبلاً با این کد آشنا شدیم، اما کاری که در این قسمت می خواهیم انجام دهیم اضافه کردن قابلیتی است که کاربر بتواند با فشردن کلید های Ctrl+C عملیات را متوقف کند. برای اینکار ابتدا شئ ای از نوع کلاس CancellationTokenSource که در فضای نام System.Threading قرار دارد، در کلاس Program به صورت زیر تعریف می کنیم:

Task < int > averageTask = new Task < int > (() = >
{
    Console.WriteLine("Calculating average...");
    Console.WriteLine("Press q to cancel...");
    var sum = 0;
    for (int counter = 1; counter < = 100; counter++)
    {
        sum += counter;
        Thread.Sleep(100);
    }
    Console.WriteLine("All done.");
    return sum/100;
}, source.Token);

شئ source که در کلاس Program ایجاد کردیم متدی دارد با نام Cancel که این متد را زمانی که قصد داریم Task متوقف شود باید فراخوانی کنیم. فراخوانی این متد باید زمانی انجام شود که کاربر کلید های Ctrl+C را فشار داده است. در محیط Console، زمانی که کاربر کلید های Ctrl+C را فشار می دهد، event ای با نام CancelPressKey در کلاس Console فراخوانی می شود، پس باید این از این event برای فراخوانی متد Cancel به صورت زیر استفاده کنیم:

Console.CancelKeyPress += (sender, eventArgs) = >
{
    source.Cancel();
    eventArgs.Cancel = true;
};

به خط دوم داخل event دقت کنید، زمانی که کلید های Ctrl+C فشرده می شوند، به صورت پیش فرض کل برنامه Console متوقف می شود، برای جلوگیری از این کار مقدار خصوصیت Cancel را در شئ eventArgs به مقدار true ست می کنیم، یعنی عملیات متوقف کردن محیط کنسول به صورت دستی توسط ما انجام شده و خود سیستم نیاز به انجام کاری در این باره ندارد.

بعد از Subscribe کردن event بالا، باید به برنامه بگوییم تا زمانی که task به اتمام نرسیده یا کاربر کلید های Ctrl+C را فشار نداده نباید از برنامه خارج شویم، به همین خاطر یک حلقه while به صورت زیر ایجاد می کنیم:

while (!averageTask.IsCompleted &amp;&amp; !source.IsCancellationRequested)
{                                                                                                
}

با خصوصیت IsCompleted در کلاس Task قبلاً آشنا شدیم، اما خصوصیت IsCancellationRequested در شئ source زمانی مقدارش true می شود که متد Cancel فراخوانی شود، پس تا زمانی که عملیات Task به اتمام نرسیده و زمانی که کاربر کلید های Ctrl+C را فشار نداده برنامه در حلقه while منتظر می ماند.

در ادامه باید Task ایجاد شده را به صورتی تغییر دهیم که داخل حلقه for بررسی شود که متد Cancel فراخوانی شده است یا خیر، اگر فراخوانی شده بود باید از Task خارج شویم، برای این کار نیز از خصوصیت IsCancellationRequested در شئ source استفاده می کنیم، Task ایجاد شده را به صورت زیر تغییر می دهیم:

Task < int > averageTask = new Task < int > (() = >
{
    Console.WriteLine("Calculating average...");
    Console.WriteLine("Press Ctrl+C to cancel...");
    var sum = 0;
    for (int counter = 1; counter < = 100; counter++)
    {
        if (source.IsCancellationRequested)
        {
            Console.WriteLine("Operation terminated!");
            return 0;
        }
        sum += counter;
        Thread.Sleep(100);
    }
    Console.WriteLine("All done.");
    return sum/100;
}, source.Token);

همانطور که مشاهده می کنید داخل حلقه for گفتیم که اگر IsCancellationRequested برابر true بود پیغامی را نمایش بده و مقدار 0 را برگردان. کد نهایی ما به صورت زیر می باشد:

class Program
{
    private static CancellationTokenSource source = new CancellationTokenSource();
    static void Main(string[] args)
    {
        Task < int > averageTask = new Task < int >(() = >
        {
            Console.WriteLine("Calculating average...");
            Console.WriteLine("Press Ctrl+C to cancel...");
            var sum = 0;
            for (int counter = 1; counter <= 100; counter++) { if (source.IsCancellationRequested) { Console.WriteLine("Operation terminated!"); return 0; } sum += counter; Thread.Sleep(100); } Console.WriteLine("All done."); return sum/100; }, source.Token); averageTask.Start(); Console.CancelKeyPress += (sender, eventArgs) = >
        {
            source.Cancel();
            eventArgs.Cancel = true;
        };
        while (!averageTask.IsCompleted && !source.IsCancellationRequested)
        {                                                                                                
        }
 
        Console.WriteLine(averageTask.Result);
    }
}

در صورتی که برنامه بالا را اجرا کرده و کلید های Ctrl+C را فشار دهیم خروجی زیر برای ما نمایش داده می شود:

Calculating average...
Press Ctrl+C to cancel...
Operation terminated!
0
Press any key to continue . . .

استفاده از CancellationToken در کلاس Parallel

علاوه بر کلاس Task می توان از قابلیت CancellationToken در متدهای کلاس Parallel نیز استفاده کرد، برای آشنایی بیشتر فرض کنید کدی به صورت زیر تعریف شده که لیست فایل های jpg داخل یک پوشه را پردازش می کند:

var jpegFiles = System.IO.Directory.GetFiles("D:\\Images", "*.jpg");
 
Parallel.ForEach(jpegFiles, file = >
{
    var fileInfo = new FileInfo(file);
    // process file
});

برای متوقف کردن عملیات پردازش فایل ها، ابتدا شئ ای از نوع CancellationTokenSource مانند مثال قبل ایجاد می کنیم:

private static CancellationTokenSource source = new CancellationTokenSource();

در قدم بعدی کلاسی از نوع ParallelOptions به صورت زیر تعریف کرده، خصوصیت CancellationToken را برابر خصوصیت Token در شئ source قرار داده و این کلاس را به عنوان پارامتر ورودی به متد ForEach به صورت زیر ارسال می کنیم:

ParallelOptions options = new ParallelOptions();
options.CancellationToken = source.Token;
 
try
{
    Parallel.ForEach(jpegFiles,options, file = >
    {
        options.CancellationToken.ThrowIfCancellationRequested();                                                
        var fileInfo = new FileInfo(file);
        // process file
    });
}
catch (OperationCanceledException ex)
{
    Console.WriteLine(ex);
}

دقت کنید در قسمت ForEach متدی با نام ThrowIfCancellationRequested فراخوانی شده است، در حقیقت این متد بعد از فراخوانی بررسی می کند که آیا متد Cancel برای شئ source فراخوانی شده است یا خیر، اگر فراخوانی شده بود خطایی از نوع OperationCanceledException ایجاد می شود که در خارج از بدنه ForEach کلاس Parallel، بوسیله ساختار try..catch این خطا مدیریت شده است. دقت کنید که روند مدیریت Cancel کردن در کلاس Parallel با کلاس Task متفاوت است و دلیل این موضوع نوع برخورد برنامه با این کلاس ها است. در قسمت بعدی با مبحث Parallel LINQ آشنا خواهیم شد.

منبع



قسمت اول آموزش-برنامه نویسی Asynchronous – آشنایی با Process ها، Thread ها و AppDomain ها

قسمت دوم آموزش- آشنایی با ماهیت Asynchronous در Delegate ها

قسمت سوم آموزش-آشنایی با فضای نام System.Threading و کلاس Thread

قسمت چهارم آموزش- آشنایی با Thread های Foreground و Background در دات نت

قسمت پنجم آموزش- آشنایی با مشکل Concurrency در برنامه های Multi-Threaded و راهکار های رفع این مشکل

قسمت ششم آموزش- آشنایی با کلاس Timer در زبان سی شارپ

قسمت هفتم آموزش-آشنایی با CLR ThreadPool در دات نت

قسمت هشتم آموزش- مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

قسمت نهم آموزش- برنامه نویسی Parallel:آشنایی با کلاس Task در سی شارپ

قسمت دهم آموزش-برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

قسمت یازدهم آموزش- برنامه نویسی Parallel در سی شارپ :: کوئری های Parallel در LINQ

قسمت دوازدهم آموزش- آشنایی با کلمات کلیدی async و await در زبان سی شارپ

قسمت سیزدهم آموزش- استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

آشنایی با کلمات کلیدی async و await در زبان سی شارپ

تا این لحظه از مجموعه مطالب مرتبط با مباحث Asynchronous Programming در سی شارپ با ماهیت Asynchronous در delegate ها، کار با Thread ها و کتابخانه TPL در دات نت آشنا شدیم. اما باز هم در برخی سناریو ها و انجام کارهای پیچیده در برنامه نویسی Asynchronous، نیاز به حجم زیادی از کدها دارد.

از نسخه 4.5 دات، در زبان سی شارپ (و همینطور زبان VB) دو کلمه کلیدی اضافه شد که اجازه نوشتن کدهای Asynchronous را به شکل دیگری به برنامه نویسان می داد. این دو کلمه کلیدی، کلمات async و await هستند و زمانی که شما در کدهای خود از این دو کلمه کلیدی استفاده می کنید، در زمان کامپایل کدها، کامپایلر کدهایی را برای شما تولید می کند که به صورت بهینه و البته مطمئن کارهای Asynchronous را برای شما انجام می دهند، کدهای تولید شده از کلاس هایی که در فضای نام System.Threading.Tasks قرار دارند استفاده می کنند.

نگاه اولیه با ساختار async و await

زمانی که شما در بخشی از کد خود از کلمه کلیدی async و بر روی متدها، عبارات لامبدا یا متدهای بدون نام استفاده می کنید، در حقیقت می گویید که این قطعه کد به صورت خودکار باید به صورت Asynchronous فراخوانی شود و زمان استفاده از کدی که به صورت async تعریف شده، CLR به صورت خودکار thread جدیدی ایجاد کرده و کد را اجرا می کند. اما زمان فراخوانی کدهایی که به صورت async تعریف شده اند، استفاده از کلمه await این امکان را فراهم می کند که اجرای thread جاری تا زمان تکمیل اجرای کدی که به صورت async تعریف شده، می بایست متوقف شود.

برای آشنایی بیشتر برنامه ای از نوع Windows Forms Application ایجاد کرده، یک Button بر روی فرم قرار می دهیم. زمانی که بر روی Button ایجاد شده کلیک می شود، یک متد دیگر فراخوانی شده و بعد از یک وقفه 10 ثانیه ای عبارتی را بر میگرداند و در نهایت این متن به عنوان Title برای فرم برنامه ست می شود:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }
 
    private void CallButton_Click(object sender, EventArgs e)
    {
        this.Text = DoWork();
    }
 
    private string DoWork()
    {
        Thread.Sleep(10000);
        return "Done.";
    }
}

مشکلی که وجود دارد این است که بعد از کلیک بر روی Button ایجاد شده، 10 ثانیه باید منتظر شده تا عنوان فرم تغییر کند. اما با انجام یکسری تغییرات در کد بالا، می توان بوسیله کلمات کلیدی async و await کاری کرد که عملیات اجرای متد به صورت Asynchronous انجام شود. برای اینکار کد بالا را به صورت زیر تغییر می دهیم:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }
 
    private async void CallButton_Click(object sender, EventArgs e)
    {
        this.Text = await DoWork();
    }
 
    private Task<string> DoWork()
    {
        return Task.Run(() = >
        {
            Thread.Sleep(10000);
            return "Done.";
        });
    }
}

بعد از اجرای برنامه، خواهیم دید که فرم ما به قول معروف block نمی شود، یعنی تا زمان اتمام فراخوانی DoWork می توانیم کارهای دیگری در فرم انجام دهیم. اگر در کد بالا دقت کنید، متدی که برای رویداد Click دکمه CallButton تعریف شده، با کلمه کلیدی async مشخص شده، یعنی اجرای این متد باید به صورت Aynchronous انجام شود.

علاوه بر این، داخل بدنه این متد، زمان فراخوانی DoWork از کلمه await استفاده کردیم، دقت کنید که نوشتن کلمه کلیدی await اینجا الزامی است، اگر این کلمه کلیدی نوشته نشود، زمان اجرای DoWork باز هم عملیات فراخوانی متد باعث block شدن فرم ما می شود. همچنین دقت کنید که متد DoWork به جای اینکه مقدار string برگرداند، مقداری از نوع <Task<string بر میگرداند. به طور خلاصه کاری که DoWork انجام می دهد به صورت زیر است:

زمانی که متد DoWork فراخوانی می شود، یک Task جدید اجرا می شود و داخل Task ابتدا عملیات اجرای Thread به مدت 10 ثانیه متوقف می شود و بعد از 10 ثانیه یک رشته به عنوان خروجی برگردانده می شود. البته این رشته تحت یک شئ از نوع Task به متدی که DoWork را فراخوانی کرده بازگردانده می شود.

با تعریف بالا، شاید بتوان بهتر نقش کلمه کلیدی await را متوجه شد، زمانی که برنامه به کلمه کلیدی await می رسد، در حقیقت منتظر می ماند تا عملیات فراخوانی متدی که await قبل از آن نوشته شده به اتمام برسد، سپس مقدار خروجی از داخل Task مربوطه برداشته شده و داخل خصوصیت Text قرار داده می شود.

قواعد نام گذاری برای متدهای Async

همانطور که گفتیم، داخل متدهایی که با async مشخص شده اند، حتماً می بایست کلمه کلیدی await نیز نوشته شود. اما از کجا بدانیم کدام متدها می توانند به صورت Async فراخوانی شوند؟ یعنی نوع خروجی آن ها یک Task است؟ اصطلاحاً به متدهایی که خروجی آن ها از نوع <Task<T است Awaitable گفته می شود. برای اینکار باید از قواعد نامگذاری متدهای Async پیروی کنیم. بر اساس مستندات مایکروسافت، می بایست کلیه متدهایی که مقدار خروجی آن ها از نوع Task است، به صورت async تعریف شوند و در انتهای نام متد کلمه Async نوشته شود، بر اساس مطالب گفته شده، متد DoWork را به صورت زیر تغییر می دهیم:

private async Task<string> DoWorkAsync()
{
    return await Task.Run(() = >
    {
        Thread.Sleep(10000);
        return "Done.";
    });
}

با انجام تغییرات بالا، کد رویداد Click را برای CallButton به صورت زیر تغییر می دهیم:

private async void CallButton_Click(object sender, EventArgs e)
{
    this.Text = await DoWorkAsync();
}

متدهای Async با مقدار خروجی void

در صورتی که متدی که قرار است به صورت async فراخوانی شود، مقدار خروجی ندارد می توان نوع خروجی متد را از نوع کلاس غیر جنریک Task انتخاب کرد و کلمه کلیدی return را ننوشت:

private async Task DoWorkAsync()
{
    await Task.Run(() = >
    {
        Thread.Sleep(10000);
    });
}

فراخوانی این متد نیز به صورت زیر خواهد بود:

await DoWorkAsync();
MessageBox.Show("Done.");

متدهای async با چندین await

یکی از قابلیت های async و await، نوشتن چندین قسمت await در یک متد async است. نمونه کد زیر حالت گفته شده را نشان می دهد:

private async void CallButton_Click(object sender, EventArgs e)
{
    await Task.Run(() = > { Thread.Sleep(5000); });
    MessageBox.Show("First Task Done!");
 
    await Task.Run(() = > { Thread.Sleep(5000); });
    MessageBox.Show("Second Task Done!");
 
    await Task.Run(() = > { Thread.Sleep(5000); });
    MessageBox.Show("Third Task Done!");
}

دقت کنید که برای await های بالا متدی تعریف نکردیم و تنها در مقابل آن متد Run از کلاس Task را فراخوانی کردیم. البته این موضوع ربطی به چند await بودن متد ندارد و شما می تواند متد هایی که خروجی آن ها از نوع Task است را نیز فراخوانی کنید، این حالت تنها برای مثال به این صورت نوشته شده است.

منبع


قسمت اول آموزش-برنامه نویسی Asynchronous – آشنایی با Process ها، Thread ها و AppDomain ها

قسمت دوم آموزش- آشنایی با ماهیت Asynchronous در Delegate ها

قسمت سوم آموزش-آشنایی با فضای نام System.Threading و کلاس Thread

قسمت چهارم آموزش- آشنایی با Thread های Foreground و Background در دات نت

قسمت پنجم آموزش- آشنایی با مشکل Concurrency در برنامه های Multi-Threaded و راهکار های رفع این مشکل

قسمت ششم آموزش- آشنایی با کلاس Timer در زبان سی شارپ

قسمت هفتم آموزش-آشنایی با CLR ThreadPool در دات نت

قسمت هشتم آموزش- مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

قسمت نهم آموزش- برنامه نویسی Parallel:آشنایی با کلاس Task در سی شارپ

قسمت دهم آموزش-برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

قسمت یازدهم آموزش- برنامه نویسی Parallel در سی شارپ :: کوئری های Parallel در LINQ

قسمت دوازدهم آموزش- آشنایی با کلمات کلیدی async و await در زبان سی شارپ

قسمت سیزدهم آموزش- استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

 

مقالات پیرامون تشخیص اعداد و حروف دست نویس فارسی

 

1. ارائه یک روش ساختاری جدید مبتنی بر قطعه بندی تصویر نازک شده برای شناسایی اعداد دست نویس فارسی/عربی

چکیده- در این مقاله، یک روش ساختاری جدید برای استخراج ویژگی از اعداد فارسی/عربی دست نوشته، ارائه شده است. پس از پیش پردازش اولیه و تبدیل تصویر به تصویر باینری، ابتدا رقم دست نوشته، نازک شده و اسکلت آن از تصویر استخراج می شود. سپس نقاط مهم تصویر به دست آمده مشخص می شوند. رقم نازک شده به قطعه خط هایی تقسیم می شود و از هر قطعه، کدهای اولیه استخراج می شود. در نهایت یک بردار ویژگی به دست می آید که طول آن به تعداد قطعه خط ها بستگی دارد. یک مقایسه بین روش ساختاری ارائه شده و روش های آماری دیگر مانند روش های مبتنی بر تبدیل موجک، فرکتال و زرنیک، از نظر زمانی و درصد تشخیص انجام شده است. نتایج نشان می دهند که عملکرد این ویژگیهای ساختاری بسیار بهتر از ویژگی های آماری است. درصد تشخیص با این ویژگی ها و با طبقه بندی کننده مبتنی بر نزدیکترین همسایه، 94/44% به دست آمد. این آزمایشات بر روی دادگانی شامل 480 نمونه برای هر رقم انجام شد که 280 نمونه برای آموزش و 200 نمونه برای آزمایش به کار گرفته شدند.

کلمات کلیدی- روش ساختاری جدید، تشخیص دست نوشته، اعداد فارسی

فایل PDF – در 7 صفحه- نویسندگان: مجید زیارت بان، کریم فائز، سعید مظفری، مهدی ازوجی

ارائه یک روش ساختاری جدید مبتنی بر قطعه بندی تصویر نازک شده برای شناسایی اعداد دست نویس فارسی یا عربی

پسورد فایل : behsanandish.com


2.  بازشناسی برخط حروف مجزای فارسی با شبکه عصبی

چکیده- در این مقاله روشی برای بازشناسی برخط حروف مجزای فارسی با شبکههای عصبی ارائه می شود. پس از بازشناسی علامت های بالا یا پایین حرف ناشناخته، بدنه ی حرف از نظر تعداد نقاط و اندازه نرمالیزه می شود و مختصات نقاط بدنه ی نرمالیزه شده به عنوان ورودی یک شبکه ی عصبی سه لایه در نظر گرفته می شود و بدنه ی حرف ناشناخته بازشناسی می شود. میزان بازشناسی درست برای 4144 حرف، 93/9% است.

واژه های کلیدی- بازشناسی برخط، حروف مجزا،شبکه ی عصبی

فایل PDF – در 7 صفحه- نویسندگان: سید محمد رضوی، احسان اله کبیر

بازشناسی برخط حروف مجزای فارسی با شبکه عصبی

پسورد فایل : behsanandish.com


3. کاربرد ترکیب طبقه ها در بازشناسی ارقام فارسی

چکیده- در این تحقیق، برای بهبود بازشناسی ارقام دستنویس از ترکیب طبقه بندی هایی استفاده می شود که از یک الگوریتم یادگیری دو مرحله ای بهره می گیرند. از تصویر هر رقم دستنویس، یک بردار ویژگی با 81 مؤلفه استخراج می شود. به روش تحلیل مؤلفه های اصلی، یک بردار ویژگی با پانزده مؤلفه برای هر رقم انتخاب شده و به سه شبکه عصبی پرسپترون با تعداد نرون های متفاوت در لایه مخفی و وزن های اولیه متفاوت اعمال شده و بازشناسی مستقل در هر طبقه بند صورت می گیرد. در مرحله بعد، نتایج بازشناسی این سه طبقه بند، به یک شبکه عصبی پرسپترون با یک لایه مخفی به عنوان ترکیب کننده اعمال می شود.

پایگاه داده استفاده شده شامل 2430 نمونه است. نرخ بازشناسی شبکه های عصبی پایه بر روی 530 نمونه آزمایشی 87% ، 85% و 83% و برای سیستم مرکب 91% است.

واژه های کلیدی- بازشناسی ارقام، ترکیب طبقه بندها، شبکه عصبی پرسپترون، مکان مشخصه، تحلیل مؤلفه های اصلی.

فایل PDF – در 5 صفحه- نویسندگان: سید حسن نبوی کریزی، رضا ابراهیم پور، احسان اله کبیر

کاربرد ترکیب طبقه ها در بازشناسی ارقام فارسی

پسورد فایل : behsanandish.com


4. بازشناسی حروف برخط فارسی با استفاده از مدل مخفی مارکوف

چکیده- در این مقاله، روشی برای بازشناسی حروف برخط فارسی که به صورت تنها نوشته شده اند، معرفی شده است. با توجه به شکل و ساختار بدنه اصلی، حروف فارسی به 17 گروه تقسیم می شوند. ابتدا، با استفاده از روش آماری مدل مخفی مارکوف به بازشناسی بدنه اصلی پرداخته شده است. در گام بعدی، بازشناسی نهایی در هر گروه با توجه به موقعیت علائم، نقاط و مدل مخفی مارکوف آن ها انجام شده است. روش پیشنهادی بر روی مجموعه داده “حروف برخط دانشگاه تربیت مدرس” اجرا شده و گروه بندی درست با دقت 96% و بازشناسی حروف با دقت 94% به دست آمده است.

کلمات کلیدی- دستنوشته برخط، فارسی، بازشناسی، مدل مخفی مارکوف.

فایل PDF – در 6 صفحه- نویسندگان: وحید قدس، احسان اله کبیر

بازشناسی حروف برخط فارسی با استفاده از مدل مخفی مارکوف

پسورد فایل : behsanandish.com


5.بازشناسی ارقام دستنویس فارسی مقاوم در برابر چرخش و تغییر مقیاس توسط طبقه بندی کننده SVM فازی مبتنی بر خوشه بند K-means

چکیده- در این مقاله روشی را برای تشخیص این ارقام معرفی کردیم که در برابر چرخش و تغییر مقیاس تا حد قابل قبولی مقاوم می باشد. در این مقاله هم برای استخراج ویژگی و هم برای طبقه بندی از دو روش مجزا استفاده کردیم. در مرحله اول برای استخراج ویژگی از آنالیز اجزای اصلی (PCA) استفاده کرده و در نوع دیگری از استخراج ویژگی از آنالیز تفکیک کننده ی خط (LDA) که برای کاهش ابعاد LDA، از تکنینک PCA استفاده کردیم. این ویژگی ها را با طبقه بندی کننده ی MLP و Fuzzy SVM به صورت جداگانه کلاسه بندی کردیم و نتایج را با هم مقایسه کردیم. برای نمایش اینکه روشمان در برابر چرخش و تغییر مقیاس مقاوم می باشد، 30 درصد کل ارقام پایگاه داده مان که متشکل از 860 رقم برای هر کدام از ارقام 0 تا 9 می باشد را با زاویه های مختلف به صورت تصادفی در جهت یا خلاف جهت عقربه ساعت چرخانه و نتایج به دست آمده را با حالت بدون چرخش مقایسه کردیم. نرخ بازشناسی روش پیشنهادی بر روی 7600 نمونه آزمایشی در حالت بدون چرخش، 97/3% به دست آمده که نسبت به نرخ بازشناسی همین پایگاه داده، در [1] و [2] به ترتیب 15/4% و 1/9% بهبود را نشان می دهد.

کلمات کلیدی- ارقام دستنویس، PCA-LDA، Fuzzy SVM، MLP، PCA

فایل PDF – در 6 صفحه- نویسنده: مهدی صالح پور

بازشناسی ارقام دستنویس فارسی مقاوم در برابر چرخش و تغییر مقیاس توسط طبقه بندی کننده SVM فازی مبتنی بر خوشه بند K-means

پسورد فایل : behsanandish.com


6. بررسی تأثیر ارتقاء تصویر و اصلاح شیب در بهبود نرخ بازشناسی ارقام جدا شده از اسناد دست نویس فارسی

چکیده- در این مقاله برای اولین بار میزان تأثیر ارتقاء تصویر و اصلاح شیب موجود در ارقام دست نویس فارسی، بر بهبود نرخ بازشناسی ارقام مورد بررسی قرار گرفته است. در ابتدا به دلیل اینکه جداسازی ارقام از تصاویر اسناد دست نویس منجر به ایجاد شکاف هایی در تصاویر ارقام جدا شده می شود، از عنصر ساختاری مناسبی برای ارتقاء تصاویر استفاده شده است. در گام بعدی، شیب موجود در ارقام، تخمین زده شده و اصلاح می گردد. بانک اطلاعاتی استفاده شده در این مقاله شامل ارقام جدا شده (4096 رقم در مجموعه آموزشی و 1532 رقم در مجموعه آزمایشی) از فرم هایی با پس زمینه ی رنگی است که توسط 500 نویسنده پر شده اند. آزمایشات انجام شده نشان می دهد که ارتقاء تصویر و اصلاح شیب در مرحله پیش پردازش، به طور میانگین نرخ بازشناسی را به میزان 3/3 درصد افزایش می دهد که نشان دهنده ی کارآمدی گام های پیشنهادی( ارتقاء تصویر و اصلاح شیب) در مرحله پیش پردازش است.

کلمات کلیدی- ارتقاء تصویر، عنصر ساختاری، اصلاح شیب، ماتریس شکاف، بازشناسی ارقام دست نویس فارسی.

فایل PDF – در 5 صفحه- نویسندگان: یونس اکبری، محمدجواد جلیلی، عاطفه فروزنده، جواد صدری

بررسی تأثیر ارتقاء تصویر و اصلاح شیب در بهبود نرخ بازشناسی ارقام جدا شده از اسناد دست نویس فارسی

پسورد فایل : behsanandish.com

برنامه نویسی Parallel در سی شارپ :: مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

پیش از این ما در سری مطالب مرتبط با بحث کار با Thread با نحوه ایجاد و مدیریت Thread ها در دات نت آشنا شدیم. از نسخه 4 دات نت قابلیتی اضافه شد با نام Task Parallel Programming یا TPL که روش جدیدی برای نوشتن برنامه Multi-Theaded است. این قابلیت بوسیله یکسری از کلاس ها که در فضای نام System.Threading.Tasks قرار دارد فراهم شده و به ما این اجازه را می دهد که بدون درگیر شدن مستقیم با Thread ها و Thread Pool ها برنامه های Multi-Threaded بنوسیم.

دقت کنید که زمان استفاده از قابلیت TPL دیگر نیازی به استفاده از کلاس های فضای نام System.Threading نمی باشد و به صورت پشت زمینه عملیات ساخت و مدیریت Thread ها برای ما انجام می شود. با این کار شیوه کار با Threadها بسیار ساده شده و یکسری از پیچیدگی ها در این بین حذف می شود.

فضای نام System.Threading.Tasks

همانطور که گفتیم TPL در حقیقت مجموعه ای از کلاس ها است که در فضای نام System.Threading.Tasks قرار گرفته. یکی از قابلیت های TPL این است که کارهای محوله را به صورت خودکار بین CPU های سیستم (در صورت وجود) توزیع می کند که این کار در پشت زمینه بوسیله CLR Thread Pool انجام می شود.

کارهای انجام شده توسط TPL در پشت زمینه عبارتند از تقسیم بندی وظایف، زمانبندی Thread ها، مدیریت وضعیت (State Management) و یکسری از کارهای اصطلاحاً Low-Level دیگر. نتیجه این کار برای شما بالا رفتن کارآیی برنامه ها بوده بدون اینکه درگیر پیچیدگی های کار با Thread ها شوید. همانطور که گفتیم فضای نام System.Threading.Tasks شامل یکسری کلاس ها مانند کلاس Parallel، کلاس Task و … می باشد که در ادامه با این کلاس ها بیشتر آشنا می شویم.

نقش کلاس Parallel

یکی از کلاس های TPL که نقش کلیدی را در نوشتن کدهای Parallel ایفا می کند، کلاس Parallel است، این کلاس یکسری متدها در اختیار ما قرار می دهد که بتوانیم بر روی آیتم های یک مجموعه (علی الخصوص مجموعه هایی که اینترفیس IEnumerable را پیاده سازی کرده اند) به صورت parallel عملیات هایی را انجام دهیم.

متدهای این کلاس عبارتند از متد های For و ForEach که البته Overload های متفاوتی برای این متدها وجود دارد. بوسیله این متدها می توان کدهایی نوشتن که عملیات مورد نظر را به صورت parallel بر روی آیتم های یک مجموعه انجام دهند. دقت کنید کدهایی که برای این متدها نوشته می شوند در حقیقت همان کدهایی هستند که معمولاً در حلقه های for و foreach استفاده می شوند، با این تفاوت که به صورت parallel اجرا شده و اجرا و مدیریت کدها بوسیله thread ها و CLR Thread Pool انجام شده و البته بحث همزمانی نیز به صورت خودکار مدیریت می شود.

کار با متد ForEach

در ابتدا به سراغ متد ForEach می رویم، این متد یک مجموعه که ایترفیس IEnumerable را پیاده سازی کرده به عنوان پارامتر اول و متدی که باید بر روی هر یک اعضای این مجموعه انجام شود را به عنوان پارامتر دوم قبول می کند:

var numbers = new List &lt; int &gt; {2, 6, 8, 1, 3, 9, 6, 10, 5, 4};
Parallel.For(3, 6, index  = &gt;
{
    Console.WriteLine(numbers[index]);
    Console.WriteLine("Thread Id: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
});

در کد بالا یک آرایه از لیست از نوع int تعریف کرده و در مرحله بعد بوسیله متد ForEach در کلاس Parallel اعضای لیست را پردازش می کنیم، با هر بار اجرا خروجی های متفاوتی دریافت خواهیم کرد:

8
5
Thread Id: 6
4
2
Thread Id: 1
6
3
Thread Id: 5
9
Thread Id: 5
10
Thread Id: 5
1
Thread Id: 5
Thread Id: 4
Thread Id: 6
6
Thread Id: 1
Thread Id: 3

همانطور که مشاهده می کنید شناسه های مربوط به thread در هر بار اجرای کدی مشخص شده در متد ForEach با یکدگیر متفاوت است، دلیل این موضوع ایجاد و مدیریت Thread ها توسط CLR Thread Pool است که ممکن است با هر بار فراخوانی متد مشخص شده به عنوان پارامتر دوم یک thread جدید ایجاد شده یا عملیات در یک thread موجود انجام شود.

کار با متد For

اما علاوه بر متد ForEach متد For نیست را می توان برای پردازش یک مجموعه استفاده کرد. در ساده ترین حالت این متد یک عدد به عنوان اندیس شروع حلقه، عدد دوم به عنوان اندیس پایان حلقه و یک پارامتر که متدی با پارامتر ورودی از نوع int یا long که نشان دهنده اندیس جاری است قبول می کند، برای مثال در متد زیر بوسیله متد For لیست numbers را در خروجی چاپ می کنیم، اما نه همه خانه های آن را پس عبارت اند از:

var numbers = new List &lt; int &gt;  {2, 6, 8, 1, 3, 9, 6, 10, 5, 4};
Parallel.For(3, 6, index  = &gt;
{
    Console.WriteLine(numbers[index]);
    Console.WriteLine("Thread Id: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
});

با اجرای کد بالا خروجی زیر نمایش داده می شود، البته با هر بار اجرا ممکن است خروجی ها با هم متفاوت باشند:

1
Thread Id: 1
9
3
Thread Id: 3
Thread Id: 4

یکی از کاربردی ترین موارد برای استفاده از کلاس Parallel و متدهای For و ForEach زمانی است که قصد داریم مجموعه حجیمی از اطلاعات را پردازش کنیم و البته پردازش هر المان وابسته به سایر المان ها نیست، زیرا عملیات پردازش المان ها به دلیل اینکه در Thread های مختلف انجام می شوند، ترتیبی در زمان اجرای المان ها در نظر گرفته نشده و ممکن است آیتمی در وسط لیست قبل از آیتم ابتدای لیست پردازش شود.

برای مثال، فرض کنید قصد دارید لیستی از تصاویر را گرفته و بر روی آن ها پردازشی انجام دهید یا لیستی از فایل ها را می خواهیم پردازش کنید، در اینجور مواقع به راحتی می توان از کلاس Parallel و متدهای آن استفاده کرد. یکی از مزیت های استفاده از کلاس Task این است که علاوه بر توزیع انجام کارها در میان Thread ها، در صورت موجود بودن بیش از یک CPU در سیستم شما، از سایر CPU ها هم برای پردازش اطلاعات استفاده می کند. در قسمت بعدی در مورد کلاس Task صحبت خواهیم کرد.

منبع



قسمت اول آموزش-برنامه نویسی Asynchronous – آشنایی با Process ها، Thread ها و AppDomain ها

قسمت دوم آموزش- آشنایی با ماهیت Asynchronous در Delegate ها

قسمت سوم آموزش-آشنایی با فضای نام System.Threading و کلاس Thread

قسمت چهارم آموزش- آشنایی با Thread های Foreground و Background در دات نت

قسمت پنجم آموزش- آشنایی با مشکل Concurrency در برنامه های Multi-Threaded و راهکار های رفع این مشکل

قسمت ششم آموزش- آشنایی با کلاس Timer در زبان سی شارپ

قسمت هفتم آموزش-آشنایی با CLR ThreadPool در دات نت

قسمت هشتم آموزش- مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

قسمت نهم آموزش- برنامه نویسی Parallel:آشنایی با کلاس Task در سی شارپ

قسمت دهم آموزش-برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

قسمت یازدهم آموزش- برنامه نویسی Parallel در سی شارپ :: کوئری های Parallel در LINQ

قسمت دوازدهم آموزش- آشنایی با کلمات کلیدی async و await در زبان سی شارپ

قسمت سیزدهم آموزش- استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

کار با Thread ها در زبان سی شارپ :: آشنایی با CLR ThreadPool در دات نت

به عنوان آخرین مبحث از سری مباحث مرتبط کار با Thread ها به سراغ نقش CLR ThreadPool می رویم. در قسمت ماهیت Asynchronous در delegate ها گفتیم که بوسیله متد BeginInvoke و EndInvoke می توان یک متد را به صورت Asynchronous فراخوانی کرد، اما نکته ای که اینجا وجود دارد این است که CLR با این کار به صورت مستقیم Thread جدیدی ایجاد نمی کند!

برای کارآیی بیشتر متد BeginInvoke یک آیتم در ThreadPool ایجاد می کند که فراخوانی آن در زمان اجرا مدیریت می شود. برای اینکه بتوانیم به طور مستقیم با این قابلیت در ارتباط باشیم، کلاسی با نام ThreadPool در فضای نام System.Threading وجود دارد که قابلیت این کار را به ما می دهد.

برای مثال اگر بخواهیم فراخوانی یک متد را به Thread Pool بسپاریم، کافیست از متد استاتیکی که در کلاس ThreadPool و با نام QueueUserWorkItem وجود دارد استفاده کنیم. بوسیله این متد می توان Callback مرتبط با کار مد نظر و همچنین شئ ای که به عنوان state استفاده می شود را به این متد ارسال کنیم. در زیر ساختار این کلاس را مشاهده می کنید:

public static class ThreadPool
{
    public static bool QueueUserWorkItem(WaitCallback callback);
    public static bool QueueUserWorkItem(WaitCallback callback, object state);
} 

پارامتر WaitCallBack می تواند به هر متدی که نوع بازگشتی آن void و پارامتر ورودی آن از نوع System.Object است اشاره کند. دقت کنید که اگر مقداری برای state مشخص نکنید، به صورت خودکار مقدار null به آن پاس داده می شود. برای آشنایی بیشتر با این کلاس به مثال زیر که همان مثال نمایش اعداد در خروجی است دقت کنید، در ابتدا کلاس Printer:

public class Printer
{
    object threadLock = new object();
    public void PrintNumbers()
    {
        lock (threadLock)
        {
            Console.Write("{0} is printing numbers &gt; ", Thread.CurrentThread.Name);
            for (int counter = 0; counter &lt; 10; counter++)
            {
                Thread.Sleep(200 * new Random().Next(5));
                Console.Write("{0},", counter);
            }
            Console.WriteLine();
        }
    }
}

در ادامه کد متد Main که با استفاده از ThreadPool عملیات ایجاد Thread ها را انجام می دهد:

class Program
{
    static void Main(string[] args)
    {
        var printer = new Printer();
        for (int index = 0; index &lt; 10; index++)
            ThreadPool.QueueUserWorkItem(PrintNumbers, printer);
 
        Console.ReadLine();
    }
 
    static void PrintNumbers(object state)
    {
        var printer = (Printer) state;
        printer.PrintNumbers();
    }
}

شاید این سوال برای شما پیش بیاید که مزیت استفاده از ThreadPool نسبت به اینکه به صورت دستی عملیات ایجاد و فراخوانی thread ها را انجام دهیم چیست؟ در زیر به برخی از مزایای اینکار اشاره می کنیم:

  1. Thread Pool به صورت بهینه تعداد عملیات مدیریت thread هایی که می بایست ایجاد شوند، شروع بشوند یا متوقف شوند را برای ما انجام می دهد.
  2. با استفاده از Thread Pool شما می توانید تمرکز خود را به جای ایجاد و مدیریت Thread ها بر روی منطق و اصل برنامه بگذارید و سایر کارها را به عهده CLR بگذارید.

اما موارد زیر نیز را مد نظر داشته باشید که مزیت ایجاد و مدیریت thread ها به صورت دستی می باشند:

  1. thread های ایجاد شده توسط thread pool به صورت پیش فرض از نوع foreground هستند، همچنین شما می توانید بوسیله ایجاد thread ها به صورت دستی Priority آن ها را نیز مشخص کنید.
  2. اگر ترتیب اجرای thread ها برای شما مهم باشند یا نیاز داشته باشید thread ها را به صورت دستی حذف یا متوقف کنید این کار بوسیله thread pool امکان پذیر نیست.

با به پایان رسیدن این مطلب، بحث ما بر روی Thread ها به پایان می رسد. به امید خدا در مطالب بعدی راجع به بحث Parallel Programming صحبت خواهیم خواهیم کرد.

 

منبع


قسمت اول آموزش-برنامه نویسی Asynchronous – آشنایی با Process ها، Thread ها و AppDomain ها

قسمت دوم آموزش- آشنایی با ماهیت Asynchronous در Delegate ها

قسمت سوم آموزش-آشنایی با فضای نام System.Threading و کلاس Thread

قسمت چهارم آموزش- آشنایی با Thread های Foreground و Background در دات نت

قسمت پنجم آموزش- آشنایی با مشکل Concurrency در برنامه های Multi-Threaded و راهکار های رفع این مشکل

قسمت ششم آموزش- آشنایی با کلاس Timer در زبان سی شارپ

قسمت هفتم آموزش-آشنایی با CLR ThreadPool در دات نت

قسمت هشتم آموزش- مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

قسمت نهم آموزش- برنامه نویسی Parallel:آشنایی با کلاس Task در سی شارپ

قسمت دهم آموزش-برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

قسمت یازدهم آموزش- برنامه نویسی Parallel در سی شارپ :: کوئری های Parallel در LINQ

قسمت دوازدهم آموزش- آشنایی با کلمات کلیدی async و await در زبان سی شارپ

قسمت سیزدهم آموزش- استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

 OSD (on screen Display) Menu Setup

دوربین ها با ویژگی های متفاوت در پروژه های مختلف در محیط های متنوع شرایط نوری گوناگونی دارند. همچنین فاکتورهای دیگری هم وجود دارد که ممکن است تصویر تولید شده توسط دوربین کیفیت مورد انتظار را به ما ندهد. برای رسیدن به بهترین کیفیت تصویر، کاربران می توانند تنظیمات و ویژگی های تصویر دوربین را بر اساس محیط نصب با کمک منوی OSD انجام دهند.

Menu Setup

DWDR

تصاویر ویدئویی واضح تر و با جزئیات بیشتر. DWDR نقاط سایه ای سیاهی که در تصویر بوجود می آید را از بین می برد این قابلیت در محیط هایی که هم نقاط تیره و هم نقاط روشن دارد بسیار کاربردی است .

DWDR

SMART IR

این ویژگی از بین برنده ی نوردهی بالای چراغ های IR روی دوربین ها در شرایطی است که ممکن است فاصله ی دوربین تا جسم خیلی زیاد نباشد.

SMART IR

(DNR(Digital Noise Redctron

کاهش نویز تصویر در محیط های با نور پایین (تصویر تهیه شده در شب).
دوربین های با امکان DNR در مقایسه با دوربین هایی که امکان DNR ندارند نویز کمتری ایجاد می کنند.

(DNR(Digital Noise Redctron

HLC Highlight Compensation

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

HLC Highlight Compensation