1

This is my ActionMethod:

public IActionResult GetMember(string BCode)
{
    Info model = new Info();

    try
    {
        model.BList = GetBList();

        if (BCode != null)
        {
            model.MemberList = GetMemberList(BCode);
        }
    }
    catch (Exception ex)
    {
        TempData["Msg"] = ex.Message;
    }
    finally
    {
    }

    return View("Index", model);
}

public List<PendingListBranchWise> GetBList()
        {
            using (IDbConnection db = new SqlConnection(configuration.GetConnectionString("constr")))
            {
                return (List<PendingListBranchWise>)db.Query<PendingListBranchWise>("sp_GetClientDetails", new { value = "GetBranchList" }, commandType: CommandType.StoredProcedure);
            }
        }

public List<pendingListMemberWise> GetMemberList(string BCode)
        {
            using (IDbConnection db = new SqlConnection(configuration.GetConnectionString("constr")))
            {
                return (List<pendingListMemberWise>)db.Query<pendingListMemberWise>("sp_GetClientDetails", new { value = BCode }, commandType: CommandType.StoredProcedure);
            }
        }

It's a simple code, running two methods returning List<SelectListItem>

model.BList = GetBList();
model.MemberList = GetMemberList(BCode);

I don't want to run them in a sequential way as they are independent of each other, so the available option for me is to use threading:

Thread t = new Thread(new ThreadStart(GetBList));
t.Start();
t.Join();

It works If GetBranchList() does not have a return type, but I need to return List<SelectListItem>.

It shows a compilation error

List<PendingListBranchWise> GetBranchList()' has the wrong return type

How to return the List from this method while running it on a separate thread?

Tanwer
  • 1,503
  • 8
  • 26
  • 41

2 Answers2

2

So this is a terrific example of what the TPL (Task Parallel Library) can be used for. It's very rare that you'd actually want to deal with raw threads over a Task. The simplest rewrite of your code would be:

public async Task<IActionResult> GetMemberList(string BCode)
{
    Info model = new Info();

    try
    {
        Task<List<B>> getBListTask = Task.Run(() => GetBList());
        Task<List<Member>> memberListTask = Task.FromResult(null);
        if (BCode != null)
        {
            memberListTask = Task.Run(() => GetMemberList(BCode));
        }

        await Task.WhenAll(getBListTask, memberListTask);

        model.BList = getBListTask.Result;
        if(BCode != null)
        {
            model.MemberList = memberListTask.Result;
        }
    }
    catch (Exception ex)
    {
        TempData["Msg"] = ex.Message;
    }
    finally
    {
    }

    return View("Index", model);
}

Now a rewrite of your problem is useless without understanding it. A Task can be seen as, as its name implies, a task that needs to be done. This can be some work that returns nothing (a Task), or some work that returns a value (Task<TValue>). What the TPL does is allow you to abstract away a lot of the concurrency and synchronization issues that come with Thread. Note it doesn't end at threads, but there are much more qualified people to talk about this than myself.

What I've written basically tells the TPL to start two tasks. One for GetBList() and one for GetMemberList(). The TPL will decide how and when these tasks are run. When I have decided I want the values, in this case right before I assign the model values, I await the tasks. await basically tells the compiler to generate some intermediate code that says: "I can't continue until the task I have provided has completed running, so wake me up when it's done". In this case, the Task to be awaited is Task.WhenAll( getBListTask, memberListTask).

Then I can get the individual results from each of the Task objects.

I have very much simplified what's going on here, but it should get you started.
I'd recommend reading this answer by Jon Skeet:
Task vs Thread differences
Other answers in that thread are also very good.

EDIT I have seen you're using Dapper. Note, many of the Dapper methods have *Async variants. Remember when I said that Tasks are units of work? Any method that returns a Task has said it is a unit of work. This doesn't explicitly mean it is CPU bound work (like starting a thread and running a calculation). It could be IO bound work, like hitting a remote DB. In this case, they probably implement the Task via callbacks and interrupts. Again something you don't need to worry too much about most of the time when consuming tasks. I'd read up a bit on the async await pattern, and see if you can use the Async variants of the Dapper methods. One way would be to define GetBList as:

public async Task<List<PendingListBranchWise>> GetBListAsync()
    {
        using (IDbConnection db = new SqlConnection(configuration.GetConnectionString("constr")))
        {
            return await (List<PendingListBranchWise>)db.QueryAsync<PendingListBranchWise>("sp_GetClientDetails", new { value = "GetBranchList" }, commandType: CommandType.StoredProcedure).ConfigureAwait(false);
        }
    }

You can see here that, now GetBListAsync returns a Task, you could now replace Task.Run() => GetBlist()); with a simple GetBListAsync(). Essentially, we've pushed the delegation of the Task down the line to GetBListAsync, and through that, to QueryAsync.

1
model.BList = GetBList();

if (BCode != null)
{
    model.MemberList = GetMemberList(BCode);
}

Can be done in parallel like this:

Parallel.Invoke(
    () => { model.BList = GetBList(); },
    () => { if (BCode != null) { model.MemberList = GetMemberList(BCode); } }
);
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • Probably not, they all do basically the same thing under the hood. – nvoigt Jul 26 '18 at 12:05
  • Thanks , result is noticeable in my case , its fast – Tanwer Jul 26 '18 at 12:06
  • One more question , If we using Threading only than function is executing on different thread , but Task is different process on same thread , so does it solve UI freeze problem also in WinForm Application ? – Tanwer Jul 26 '18 at 12:09
  • Whether it's a thread or a task, if you wait for it (in this case you wait for two things in parallel, but you still wait) your UI will freeze. You will need to be either really `async`/`await` or do something that is different from blocking wait. – nvoigt Jul 26 '18 at 12:14