Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to launch several operations side-by-side in .net?

I have an application that takes too long to run, and I want to introduce threading / parallelization / whatever.

Specifically, the code retreives several thousand mails, then sends them. Today, the code looks like this (a bit simplified) :

Dim mails = centreInteretService.GetEmails()
For Each m in mails
    m.Body = GetMailContent(m)
    If MailSendable(m) Then
        SendMail(m)
    End If
Next

I want to try sending multiple mails in parallel. I would like to try with 2 threads in parallel. More specifically, I would want to put the whole loop in a thread (getmailcontent + sendmail).

I thought of something like this :

Dim mails1 As New List(Of MailSerialiserCI)
Dim mails2 As New List(Of MailSerialiserCI)
Dim nbFirstList As Integer = CInt(Math.Ceiling(nbTotal / 2))
mails1 = mails.Take(nbFirstList)
mails2 = mails.Skip(nbFirstList)

Dim smt1 As New MailSender.MailSenderThreaded()
smt1.mails = mails1
smt1.nbTotal = nbTotal
Dim threadMails1 As ThreadStart = New ThreadStart(AddressOf smt1.SendMails)
Dim th1 As Thread = New Thread(AddressOf threadMails1)
th1.Start()

Dim smt2 As New MailSender.MailSenderThreaded()
smt2.mails = mails2
smt2.nbTotal = nbTotal
Dim threadMails2 As ThreadStart = New ThreadStart(AddressOf smt2.SendMails)
Dim th2 As Thread = New Thread(AddressOf threadMails2)
th2.Start()

And MailSenderThreaded is like this :

Public Class MailSenderThreaded
    Public mails As List(Of MailSerialiserCI)
    Public nbTotal As Integer
    Public Sub SendMails()
        LoopMails(Me.mails, Me.nbTotal)
    End Sub
End Class

But the lines with New Thread(AdressOf x) give me an error : no applicable function x matching delegate System.Threading.ParameterizedThreadStart.

I tried searching here and there, but I can only find either solutions that require a lot more knowledge than what I have ; or threading basics ; or .NET 4 stuff, but we are still in .NET 3.5...

Do you have a simple solution that I could try ?

Thanks

like image 320
thomasb Avatar asked Jan 02 '12 11:01

thomasb


1 Answers

If the body of your loop is thread-safe, you could just use Parallel.ForEach

In C#, it would look like this:

var mails = centreInteretService.GetEmails();

Parallel.ForEach( mails, new ParallelOptions { MaxDegreeOfParallelism = 2 }, m =>
    {
        m.Body = GetMailContent(m);
        if ( MailSendable(m) ) SendMail(m);
    }
);

EDIT: .NET 3.5!

I think this is about the simplest solution in .NET 3.5:

( Sorry it's in C# - I don't know VB. I hope you can read it. )

...
List<Mail> mails = centreInteretService.GetEmails();
var mailer = new Mailer( mails );
mailer.Run();
...

public class Mailer
{
    const int THREAD_COUNT = 2;
    List<Thread> _Threads = new List<Thread>();

    List<Mail> _List = null;
    int _Index = -1;

    public Mailer( List<Mail> list )
    {
        _List = list;
    }

    public void Run()
    {
        for ( int i = 0 ; i < THREAD_COUNT ; i++ )
        {
            _Threads.Add( StartThread() );
        }

        foreach ( var thread in _Threads ) thread.Join();
    }

    Thread StartThread()
    {
        var t = new Thread( ThreadMain );
        t.Start();
        return t;
    }

    void ThreadMain()
    {
        for ( ; ; )
        {
            int index = Interlocked.Increment( ref _Index );
            if ( index >= _List.Count ) return;
            ThreadWork( _List[ index ] );
        }
    }

    void ThreadWork( Mail mail )
    {
        mail.Body = GetMailContent(mail);
        if ( MailSendable(mail) ) SendMail(mail);
    }
}
like image 120
Nick Butler Avatar answered Oct 03 '22 07:10

Nick Butler