Task Parallel Library and Long Running Tasks









up vote
-2
down vote

favorite












I have a BackgroundService (IHostedService) that implements ExecuteAsync similar to the example in Implement background tasks in microservices with IHostedService and the BackgroundService class.



I want to run several tasks that execute a long running command in an external system simultaneously. I want the service to continue executing these tasks until the service is stopped - but I don't want to execute the command with the same parameters at the same time (if it's executing with item.parameter1 = 123 I want it to wait until 123 is done, then execute with 123 again). Also, it should not block and it should not leak memory. If an exception occurs I'd like to stop the offending task gracefully, log it and restart. Each execution of the command gets different parameters, so something like this:



protected override async Task ExecuteAsync(CancellationToken stoppingToken)

var items = GetItems(); //GetItems returns a List<Item>

_logger.LogDebug($"ExternalCommandService is starting.");

stoppingToken.Register(() =>
_logger.LogDebug($" Execute external command background task is stopping."));

while (!stoppingToken.IsCancellationRequested)

_logger.LogDebug($"External command task is doing background work.");

//Execute the command with values from the item
foreach(var item in items)

ExecuteExternalCommand(item);


await Task.Delay(_settings.CheckUpdateTime, stoppingToken);


_logger.LogDebug($"Execute external command background task is stopping.");




The structure of the data is pretty simple:



public class MyData

public string Foo get; set;
public string Blee get; set;



I'm a complete newbie when it comes to Task development so please forgive my lack of understanding. Would it make more sense to make ExecuteExternalCommand asynchronous? I'm not certain that these tasks are being executed in parallel. What am I doing wrong? How do I accomplish the other requirements like exception handling and graceful restarting of the tasks? Please help.










share|improve this question























  • What is in QueryTheDatabase?
    – Peter Bons
    Nov 10 at 20:29











  • It's a synchronous method that calls a long running command in another system. The name I gave it here doesn't accurately reflect what it does, I'll update it.
    – TrevorBrooks
    Nov 10 at 21:30






  • 1




    if ExecuteExternalCommand is a long running command, it might be worthwhile to pass it the cancellation token so it can be cancelled, otherwise your service won't stop until it returns
    – ESG
    Nov 12 at 18:36






  • 1




    How many operations are you wanting to run? It sounds like you want a unique operation for each unique type. item.parameter1 = 123 on operation that loops until stopped and so on. If so then the recommendations for Parallel may not be the best option. This is for splitting a single complex operation into many (forking and joining). I believe your work is a bit simpler where you can use a query to break out the parameters into groups or a single list and sending each one into it's own Task method that can run until stopped.
    – Michael Puckett II
    Nov 12 at 20:00






  • 1




    @TrevorBrooks if you have a lot of different tasks with different scheduling needs you should probably look at a proper job scheduler like Hangfire. ExecuteAsync is just the method called to execute whatever you want in the background.
    – Panagiotis Kanavos
    Nov 13 at 9:32














up vote
-2
down vote

favorite












I have a BackgroundService (IHostedService) that implements ExecuteAsync similar to the example in Implement background tasks in microservices with IHostedService and the BackgroundService class.



I want to run several tasks that execute a long running command in an external system simultaneously. I want the service to continue executing these tasks until the service is stopped - but I don't want to execute the command with the same parameters at the same time (if it's executing with item.parameter1 = 123 I want it to wait until 123 is done, then execute with 123 again). Also, it should not block and it should not leak memory. If an exception occurs I'd like to stop the offending task gracefully, log it and restart. Each execution of the command gets different parameters, so something like this:



protected override async Task ExecuteAsync(CancellationToken stoppingToken)

var items = GetItems(); //GetItems returns a List<Item>

_logger.LogDebug($"ExternalCommandService is starting.");

stoppingToken.Register(() =>
_logger.LogDebug($" Execute external command background task is stopping."));

while (!stoppingToken.IsCancellationRequested)

_logger.LogDebug($"External command task is doing background work.");

//Execute the command with values from the item
foreach(var item in items)

ExecuteExternalCommand(item);


await Task.Delay(_settings.CheckUpdateTime, stoppingToken);


_logger.LogDebug($"Execute external command background task is stopping.");




The structure of the data is pretty simple:



public class MyData

public string Foo get; set;
public string Blee get; set;



I'm a complete newbie when it comes to Task development so please forgive my lack of understanding. Would it make more sense to make ExecuteExternalCommand asynchronous? I'm not certain that these tasks are being executed in parallel. What am I doing wrong? How do I accomplish the other requirements like exception handling and graceful restarting of the tasks? Please help.










share|improve this question























  • What is in QueryTheDatabase?
    – Peter Bons
    Nov 10 at 20:29











  • It's a synchronous method that calls a long running command in another system. The name I gave it here doesn't accurately reflect what it does, I'll update it.
    – TrevorBrooks
    Nov 10 at 21:30






  • 1




    if ExecuteExternalCommand is a long running command, it might be worthwhile to pass it the cancellation token so it can be cancelled, otherwise your service won't stop until it returns
    – ESG
    Nov 12 at 18:36






  • 1




    How many operations are you wanting to run? It sounds like you want a unique operation for each unique type. item.parameter1 = 123 on operation that loops until stopped and so on. If so then the recommendations for Parallel may not be the best option. This is for splitting a single complex operation into many (forking and joining). I believe your work is a bit simpler where you can use a query to break out the parameters into groups or a single list and sending each one into it's own Task method that can run until stopped.
    – Michael Puckett II
    Nov 12 at 20:00






  • 1




    @TrevorBrooks if you have a lot of different tasks with different scheduling needs you should probably look at a proper job scheduler like Hangfire. ExecuteAsync is just the method called to execute whatever you want in the background.
    – Panagiotis Kanavos
    Nov 13 at 9:32












up vote
-2
down vote

favorite









up vote
-2
down vote

favorite











I have a BackgroundService (IHostedService) that implements ExecuteAsync similar to the example in Implement background tasks in microservices with IHostedService and the BackgroundService class.



I want to run several tasks that execute a long running command in an external system simultaneously. I want the service to continue executing these tasks until the service is stopped - but I don't want to execute the command with the same parameters at the same time (if it's executing with item.parameter1 = 123 I want it to wait until 123 is done, then execute with 123 again). Also, it should not block and it should not leak memory. If an exception occurs I'd like to stop the offending task gracefully, log it and restart. Each execution of the command gets different parameters, so something like this:



protected override async Task ExecuteAsync(CancellationToken stoppingToken)

var items = GetItems(); //GetItems returns a List<Item>

_logger.LogDebug($"ExternalCommandService is starting.");

stoppingToken.Register(() =>
_logger.LogDebug($" Execute external command background task is stopping."));

while (!stoppingToken.IsCancellationRequested)

_logger.LogDebug($"External command task is doing background work.");

//Execute the command with values from the item
foreach(var item in items)

ExecuteExternalCommand(item);


await Task.Delay(_settings.CheckUpdateTime, stoppingToken);


_logger.LogDebug($"Execute external command background task is stopping.");




The structure of the data is pretty simple:



public class MyData

public string Foo get; set;
public string Blee get; set;



I'm a complete newbie when it comes to Task development so please forgive my lack of understanding. Would it make more sense to make ExecuteExternalCommand asynchronous? I'm not certain that these tasks are being executed in parallel. What am I doing wrong? How do I accomplish the other requirements like exception handling and graceful restarting of the tasks? Please help.










share|improve this question















I have a BackgroundService (IHostedService) that implements ExecuteAsync similar to the example in Implement background tasks in microservices with IHostedService and the BackgroundService class.



I want to run several tasks that execute a long running command in an external system simultaneously. I want the service to continue executing these tasks until the service is stopped - but I don't want to execute the command with the same parameters at the same time (if it's executing with item.parameter1 = 123 I want it to wait until 123 is done, then execute with 123 again). Also, it should not block and it should not leak memory. If an exception occurs I'd like to stop the offending task gracefully, log it and restart. Each execution of the command gets different parameters, so something like this:



protected override async Task ExecuteAsync(CancellationToken stoppingToken)

var items = GetItems(); //GetItems returns a List<Item>

_logger.LogDebug($"ExternalCommandService is starting.");

stoppingToken.Register(() =>
_logger.LogDebug($" Execute external command background task is stopping."));

while (!stoppingToken.IsCancellationRequested)

_logger.LogDebug($"External command task is doing background work.");

//Execute the command with values from the item
foreach(var item in items)

ExecuteExternalCommand(item);


await Task.Delay(_settings.CheckUpdateTime, stoppingToken);


_logger.LogDebug($"Execute external command background task is stopping.");




The structure of the data is pretty simple:



public class MyData

public string Foo get; set;
public string Blee get; set;



I'm a complete newbie when it comes to Task development so please forgive my lack of understanding. Would it make more sense to make ExecuteExternalCommand asynchronous? I'm not certain that these tasks are being executed in parallel. What am I doing wrong? How do I accomplish the other requirements like exception handling and graceful restarting of the tasks? Please help.







c# .net-core task task-parallel-library background-service






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 12 at 23:08

























asked Nov 10 at 19:45









TrevorBrooks

1,3131030




1,3131030











  • What is in QueryTheDatabase?
    – Peter Bons
    Nov 10 at 20:29











  • It's a synchronous method that calls a long running command in another system. The name I gave it here doesn't accurately reflect what it does, I'll update it.
    – TrevorBrooks
    Nov 10 at 21:30






  • 1




    if ExecuteExternalCommand is a long running command, it might be worthwhile to pass it the cancellation token so it can be cancelled, otherwise your service won't stop until it returns
    – ESG
    Nov 12 at 18:36






  • 1




    How many operations are you wanting to run? It sounds like you want a unique operation for each unique type. item.parameter1 = 123 on operation that loops until stopped and so on. If so then the recommendations for Parallel may not be the best option. This is for splitting a single complex operation into many (forking and joining). I believe your work is a bit simpler where you can use a query to break out the parameters into groups or a single list and sending each one into it's own Task method that can run until stopped.
    – Michael Puckett II
    Nov 12 at 20:00






  • 1




    @TrevorBrooks if you have a lot of different tasks with different scheduling needs you should probably look at a proper job scheduler like Hangfire. ExecuteAsync is just the method called to execute whatever you want in the background.
    – Panagiotis Kanavos
    Nov 13 at 9:32
















  • What is in QueryTheDatabase?
    – Peter Bons
    Nov 10 at 20:29











  • It's a synchronous method that calls a long running command in another system. The name I gave it here doesn't accurately reflect what it does, I'll update it.
    – TrevorBrooks
    Nov 10 at 21:30






  • 1




    if ExecuteExternalCommand is a long running command, it might be worthwhile to pass it the cancellation token so it can be cancelled, otherwise your service won't stop until it returns
    – ESG
    Nov 12 at 18:36






  • 1




    How many operations are you wanting to run? It sounds like you want a unique operation for each unique type. item.parameter1 = 123 on operation that loops until stopped and so on. If so then the recommendations for Parallel may not be the best option. This is for splitting a single complex operation into many (forking and joining). I believe your work is a bit simpler where you can use a query to break out the parameters into groups or a single list and sending each one into it's own Task method that can run until stopped.
    – Michael Puckett II
    Nov 12 at 20:00






  • 1




    @TrevorBrooks if you have a lot of different tasks with different scheduling needs you should probably look at a proper job scheduler like Hangfire. ExecuteAsync is just the method called to execute whatever you want in the background.
    – Panagiotis Kanavos
    Nov 13 at 9:32















What is in QueryTheDatabase?
– Peter Bons
Nov 10 at 20:29





What is in QueryTheDatabase?
– Peter Bons
Nov 10 at 20:29













It's a synchronous method that calls a long running command in another system. The name I gave it here doesn't accurately reflect what it does, I'll update it.
– TrevorBrooks
Nov 10 at 21:30




It's a synchronous method that calls a long running command in another system. The name I gave it here doesn't accurately reflect what it does, I'll update it.
– TrevorBrooks
Nov 10 at 21:30




1




1




if ExecuteExternalCommand is a long running command, it might be worthwhile to pass it the cancellation token so it can be cancelled, otherwise your service won't stop until it returns
– ESG
Nov 12 at 18:36




if ExecuteExternalCommand is a long running command, it might be worthwhile to pass it the cancellation token so it can be cancelled, otherwise your service won't stop until it returns
– ESG
Nov 12 at 18:36




1




1




How many operations are you wanting to run? It sounds like you want a unique operation for each unique type. item.parameter1 = 123 on operation that loops until stopped and so on. If so then the recommendations for Parallel may not be the best option. This is for splitting a single complex operation into many (forking and joining). I believe your work is a bit simpler where you can use a query to break out the parameters into groups or a single list and sending each one into it's own Task method that can run until stopped.
– Michael Puckett II
Nov 12 at 20:00




How many operations are you wanting to run? It sounds like you want a unique operation for each unique type. item.parameter1 = 123 on operation that loops until stopped and so on. If so then the recommendations for Parallel may not be the best option. This is for splitting a single complex operation into many (forking and joining). I believe your work is a bit simpler where you can use a query to break out the parameters into groups or a single list and sending each one into it's own Task method that can run until stopped.
– Michael Puckett II
Nov 12 at 20:00




1




1




@TrevorBrooks if you have a lot of different tasks with different scheduling needs you should probably look at a proper job scheduler like Hangfire. ExecuteAsync is just the method called to execute whatever you want in the background.
– Panagiotis Kanavos
Nov 13 at 9:32




@TrevorBrooks if you have a lot of different tasks with different scheduling needs you should probably look at a proper job scheduler like Hangfire. ExecuteAsync is just the method called to execute whatever you want in the background.
– Panagiotis Kanavos
Nov 13 at 9:32












1 Answer
1






active

oldest

votes

















up vote
1
down vote



+250










You have data, that you want grouped by a particular value, and then ran in it's own loop repeatedly. I will give an example for one way of doing this that hopefully you can lean on to get what you need for your answer.



Note: This example may not be useful based on how the data is mocked. If you provide the proper data structure in your question I'll update the answer to match.



You have data.



public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";



You want the data grouped by a particular value.
(NOTE: This example may not be logical because it's grouping the data by the Value which is already unique. This is added just for example:)



There are many ways to do this but I'll use Linq, Distinct, and the IEqualityComparer<T> for this example which compares the Data.Value.



public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();



Mock the Data
For this example I'll mock some data.



var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));



Process the Data
For this example I'll use the IEqualityComparer<T> to get each Data uniquely by Value and start the processing.



private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data); //We start unique loops here.




Loop the Unique Data



For this example I chose to start a new Task using the Task.Factory. This would be one time using it makes sense but typically you don't need it.
In this example I pass in an Action<object> where object represents the state or parameter given to the Task.
I also parse the state which you will see and start a while loop. The while loop monitors the CancellationTokenSource for cancellation. I declared the CancellationTokenSource statically in the app for convenience; which you will see in the full Console App at the bottom.



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);




Now I put it all into a single Console App you can copy and paste and explore.



This will take your data, break it up, and run it all in it's all Task indefinitely until the program is ended.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Question_Answer_Console_App

class Program

private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
static void Main(string args)

var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));


ProcessData(dataItems);
Console.ReadKey();
cancellationTokenSource.Cancel();
Console.WriteLine("CANCELLING...");
Console.ReadKey();


private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data);



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);


~Program() => cancellationTokenSource?.Dispose();


public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";


public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();


//OUTPUT UNTIL CANCELLED
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 6 Text: Data: 6
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 8 Text: Data: 8
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
// CANCELLING...



In the comments you asked how to write to console when the Task is complete. You can await the Task in this example and when the Task is complete you can print that Data for show. async void isn't recommended for good reason but this is one time when it's used correctly.



Here's the updated LoopData with the async await signature.



private static async void LoopData(Data data)

await Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);

Console.WriteLine($"Task Complete: data.Value : data.Text");


//OUTPUT
//Value: 0 Text: Data: 0
//Value: 1 Text: Data: 1
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
// CANCELLING...
//Task Complete: 0 : Data: 0
//Task Complete: 2 : Data: 2
//Task Complete: 3 : Data: 3
//Task Complete: 1 : Data: 1
//Task Complete: 5 : Data: 5
//Task Complete: 4 : Data: 4
//Task Complete: 8 : Data: 8
//Task Complete: 6 : Data: 6
//Task Complete: 7 : Data: 7
//Task Complete: 9 : Data: 9..





share|improve this answer






















  • This is great, thank you...just working my way through it.
    – TrevorBrooks
    Nov 12 at 21:21










  • I have added the structure of my data.
    – TrevorBrooks
    Nov 12 at 23:09










  • Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
    – TrevorBrooks
    Nov 14 at 21:28






  • 1




    Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
    – Michael Puckett II
    Nov 14 at 23:30










  • Thank you. That line actually never gets called. :-/
    – TrevorBrooks
    Nov 15 at 13:56










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53242770%2ftask-parallel-library-and-long-running-tasks%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



+250










You have data, that you want grouped by a particular value, and then ran in it's own loop repeatedly. I will give an example for one way of doing this that hopefully you can lean on to get what you need for your answer.



Note: This example may not be useful based on how the data is mocked. If you provide the proper data structure in your question I'll update the answer to match.



You have data.



public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";



You want the data grouped by a particular value.
(NOTE: This example may not be logical because it's grouping the data by the Value which is already unique. This is added just for example:)



There are many ways to do this but I'll use Linq, Distinct, and the IEqualityComparer<T> for this example which compares the Data.Value.



public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();



Mock the Data
For this example I'll mock some data.



var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));



Process the Data
For this example I'll use the IEqualityComparer<T> to get each Data uniquely by Value and start the processing.



private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data); //We start unique loops here.




Loop the Unique Data



For this example I chose to start a new Task using the Task.Factory. This would be one time using it makes sense but typically you don't need it.
In this example I pass in an Action<object> where object represents the state or parameter given to the Task.
I also parse the state which you will see and start a while loop. The while loop monitors the CancellationTokenSource for cancellation. I declared the CancellationTokenSource statically in the app for convenience; which you will see in the full Console App at the bottom.



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);




Now I put it all into a single Console App you can copy and paste and explore.



This will take your data, break it up, and run it all in it's all Task indefinitely until the program is ended.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Question_Answer_Console_App

class Program

private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
static void Main(string args)

var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));


ProcessData(dataItems);
Console.ReadKey();
cancellationTokenSource.Cancel();
Console.WriteLine("CANCELLING...");
Console.ReadKey();


private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data);



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);


~Program() => cancellationTokenSource?.Dispose();


public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";


public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();


//OUTPUT UNTIL CANCELLED
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 6 Text: Data: 6
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 8 Text: Data: 8
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
// CANCELLING...



In the comments you asked how to write to console when the Task is complete. You can await the Task in this example and when the Task is complete you can print that Data for show. async void isn't recommended for good reason but this is one time when it's used correctly.



Here's the updated LoopData with the async await signature.



private static async void LoopData(Data data)

await Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);

Console.WriteLine($"Task Complete: data.Value : data.Text");


//OUTPUT
//Value: 0 Text: Data: 0
//Value: 1 Text: Data: 1
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
// CANCELLING...
//Task Complete: 0 : Data: 0
//Task Complete: 2 : Data: 2
//Task Complete: 3 : Data: 3
//Task Complete: 1 : Data: 1
//Task Complete: 5 : Data: 5
//Task Complete: 4 : Data: 4
//Task Complete: 8 : Data: 8
//Task Complete: 6 : Data: 6
//Task Complete: 7 : Data: 7
//Task Complete: 9 : Data: 9..





share|improve this answer






















  • This is great, thank you...just working my way through it.
    – TrevorBrooks
    Nov 12 at 21:21










  • I have added the structure of my data.
    – TrevorBrooks
    Nov 12 at 23:09










  • Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
    – TrevorBrooks
    Nov 14 at 21:28






  • 1




    Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
    – Michael Puckett II
    Nov 14 at 23:30










  • Thank you. That line actually never gets called. :-/
    – TrevorBrooks
    Nov 15 at 13:56














up vote
1
down vote



+250










You have data, that you want grouped by a particular value, and then ran in it's own loop repeatedly. I will give an example for one way of doing this that hopefully you can lean on to get what you need for your answer.



Note: This example may not be useful based on how the data is mocked. If you provide the proper data structure in your question I'll update the answer to match.



You have data.



public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";



You want the data grouped by a particular value.
(NOTE: This example may not be logical because it's grouping the data by the Value which is already unique. This is added just for example:)



There are many ways to do this but I'll use Linq, Distinct, and the IEqualityComparer<T> for this example which compares the Data.Value.



public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();



Mock the Data
For this example I'll mock some data.



var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));



Process the Data
For this example I'll use the IEqualityComparer<T> to get each Data uniquely by Value and start the processing.



private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data); //We start unique loops here.




Loop the Unique Data



For this example I chose to start a new Task using the Task.Factory. This would be one time using it makes sense but typically you don't need it.
In this example I pass in an Action<object> where object represents the state or parameter given to the Task.
I also parse the state which you will see and start a while loop. The while loop monitors the CancellationTokenSource for cancellation. I declared the CancellationTokenSource statically in the app for convenience; which you will see in the full Console App at the bottom.



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);




Now I put it all into a single Console App you can copy and paste and explore.



This will take your data, break it up, and run it all in it's all Task indefinitely until the program is ended.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Question_Answer_Console_App

class Program

private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
static void Main(string args)

var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));


ProcessData(dataItems);
Console.ReadKey();
cancellationTokenSource.Cancel();
Console.WriteLine("CANCELLING...");
Console.ReadKey();


private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data);



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);


~Program() => cancellationTokenSource?.Dispose();


public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";


public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();


//OUTPUT UNTIL CANCELLED
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 6 Text: Data: 6
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 8 Text: Data: 8
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
// CANCELLING...



In the comments you asked how to write to console when the Task is complete. You can await the Task in this example and when the Task is complete you can print that Data for show. async void isn't recommended for good reason but this is one time when it's used correctly.



Here's the updated LoopData with the async await signature.



private static async void LoopData(Data data)

await Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);

Console.WriteLine($"Task Complete: data.Value : data.Text");


//OUTPUT
//Value: 0 Text: Data: 0
//Value: 1 Text: Data: 1
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
// CANCELLING...
//Task Complete: 0 : Data: 0
//Task Complete: 2 : Data: 2
//Task Complete: 3 : Data: 3
//Task Complete: 1 : Data: 1
//Task Complete: 5 : Data: 5
//Task Complete: 4 : Data: 4
//Task Complete: 8 : Data: 8
//Task Complete: 6 : Data: 6
//Task Complete: 7 : Data: 7
//Task Complete: 9 : Data: 9..





share|improve this answer






















  • This is great, thank you...just working my way through it.
    – TrevorBrooks
    Nov 12 at 21:21










  • I have added the structure of my data.
    – TrevorBrooks
    Nov 12 at 23:09










  • Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
    – TrevorBrooks
    Nov 14 at 21:28






  • 1




    Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
    – Michael Puckett II
    Nov 14 at 23:30










  • Thank you. That line actually never gets called. :-/
    – TrevorBrooks
    Nov 15 at 13:56












up vote
1
down vote



+250







up vote
1
down vote



+250




+250




You have data, that you want grouped by a particular value, and then ran in it's own loop repeatedly. I will give an example for one way of doing this that hopefully you can lean on to get what you need for your answer.



Note: This example may not be useful based on how the data is mocked. If you provide the proper data structure in your question I'll update the answer to match.



You have data.



public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";



You want the data grouped by a particular value.
(NOTE: This example may not be logical because it's grouping the data by the Value which is already unique. This is added just for example:)



There are many ways to do this but I'll use Linq, Distinct, and the IEqualityComparer<T> for this example which compares the Data.Value.



public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();



Mock the Data
For this example I'll mock some data.



var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));



Process the Data
For this example I'll use the IEqualityComparer<T> to get each Data uniquely by Value and start the processing.



private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data); //We start unique loops here.




Loop the Unique Data



For this example I chose to start a new Task using the Task.Factory. This would be one time using it makes sense but typically you don't need it.
In this example I pass in an Action<object> where object represents the state or parameter given to the Task.
I also parse the state which you will see and start a while loop. The while loop monitors the CancellationTokenSource for cancellation. I declared the CancellationTokenSource statically in the app for convenience; which you will see in the full Console App at the bottom.



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);




Now I put it all into a single Console App you can copy and paste and explore.



This will take your data, break it up, and run it all in it's all Task indefinitely until the program is ended.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Question_Answer_Console_App

class Program

private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
static void Main(string args)

var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));


ProcessData(dataItems);
Console.ReadKey();
cancellationTokenSource.Cancel();
Console.WriteLine("CANCELLING...");
Console.ReadKey();


private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data);



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);


~Program() => cancellationTokenSource?.Dispose();


public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";


public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();


//OUTPUT UNTIL CANCELLED
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 6 Text: Data: 6
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 8 Text: Data: 8
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
// CANCELLING...



In the comments you asked how to write to console when the Task is complete. You can await the Task in this example and when the Task is complete you can print that Data for show. async void isn't recommended for good reason but this is one time when it's used correctly.



Here's the updated LoopData with the async await signature.



private static async void LoopData(Data data)

await Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);

Console.WriteLine($"Task Complete: data.Value : data.Text");


//OUTPUT
//Value: 0 Text: Data: 0
//Value: 1 Text: Data: 1
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
// CANCELLING...
//Task Complete: 0 : Data: 0
//Task Complete: 2 : Data: 2
//Task Complete: 3 : Data: 3
//Task Complete: 1 : Data: 1
//Task Complete: 5 : Data: 5
//Task Complete: 4 : Data: 4
//Task Complete: 8 : Data: 8
//Task Complete: 6 : Data: 6
//Task Complete: 7 : Data: 7
//Task Complete: 9 : Data: 9..





share|improve this answer














You have data, that you want grouped by a particular value, and then ran in it's own loop repeatedly. I will give an example for one way of doing this that hopefully you can lean on to get what you need for your answer.



Note: This example may not be useful based on how the data is mocked. If you provide the proper data structure in your question I'll update the answer to match.



You have data.



public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";



You want the data grouped by a particular value.
(NOTE: This example may not be logical because it's grouping the data by the Value which is already unique. This is added just for example:)



There are many ways to do this but I'll use Linq, Distinct, and the IEqualityComparer<T> for this example which compares the Data.Value.



public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();



Mock the Data
For this example I'll mock some data.



var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));



Process the Data
For this example I'll use the IEqualityComparer<T> to get each Data uniquely by Value and start the processing.



private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data); //We start unique loops here.




Loop the Unique Data



For this example I chose to start a new Task using the Task.Factory. This would be one time using it makes sense but typically you don't need it.
In this example I pass in an Action<object> where object represents the state or parameter given to the Task.
I also parse the state which you will see and start a while loop. The while loop monitors the CancellationTokenSource for cancellation. I declared the CancellationTokenSource statically in the app for convenience; which you will see in the full Console App at the bottom.



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);




Now I put it all into a single Console App you can copy and paste and explore.



This will take your data, break it up, and run it all in it's all Task indefinitely until the program is ended.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Question_Answer_Console_App

class Program

private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
static void Main(string args)

var dataItems = new List<Data>();

for (var i = 0; i < 10; i++)

dataItems.Add(new Data(i));


ProcessData(dataItems);
Console.ReadKey();
cancellationTokenSource.Cancel();
Console.WriteLine("CANCELLING...");
Console.ReadKey();


private static void ProcessData(List<Data> dataItems)

var groupedDataItems = dataItems.Distinct(new DataDistinction());

foreach (var data in groupedDataItems)

LoopData(data);



private static void LoopData(Data data)

Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);


~Program() => cancellationTokenSource?.Dispose();


public struct Data

public Data(int value) => Value = value;
public int Value get;
public string Text => $"nameof(Data): Value";


public class DataDistinction : IEqualityComparer<Data>

public bool Equals(Data x, Data y) => x.Value == y.Value;
public int GetHashCode(Data obj) => obj.Value.GetHashCode();


//OUTPUT UNTIL CANCELLED
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 6 Text: Data: 6
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 8 Text: Data: 8
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 2 Text: Data: 2
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 9 Text: Data: 9
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 4 Text: Data: 4
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 4 Text: Data: 4
//Value: 9 Text: Data: 9
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 5 Text: Data: 5
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 5 Text: Data: 5
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 7 Text: Data: 7
//Value: 1 Text: Data: 1
//Value: 0 Text: Data: 0
//Value: 6 Text: Data: 6
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 7 Text: Data: 7
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
// CANCELLING...



In the comments you asked how to write to console when the Task is complete. You can await the Task in this example and when the Task is complete you can print that Data for show. async void isn't recommended for good reason but this is one time when it's used correctly.



Here's the updated LoopData with the async await signature.



private static async void LoopData(Data data)

await Task.Factory.StartNew((state) =>

var taskData = (Data)state;
while (!cancellationTokenSource.IsCancellationRequested)

Console.WriteLine($"Value: taskData.ValuetText: taskData.Text");
Task.Delay(100).Wait();

,
data,
cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);

Console.WriteLine($"Task Complete: data.Value : data.Text");


//OUTPUT
//Value: 0 Text: Data: 0
//Value: 1 Text: Data: 1
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 1 Text: Data: 1
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 1 Text: Data: 1
//Value: 4 Text: Data: 4
//Value: 5 Text: Data: 5
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 8 Text: Data: 8
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 0 Text: Data: 0
//Value: 3 Text: Data: 3
//Value: 2 Text: Data: 2
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 5 Text: Data: 5
//Value: 8 Text: Data: 8
//Value: 9 Text: Data: 9
//Value: 6 Text: Data: 6
//Value: 7 Text: Data: 7
//Value: 0 Text: Data: 0
//Value: 2 Text: Data: 2
//Value: 3 Text: Data: 3
//Value: 5 Text: Data: 5
//Value: 4 Text: Data: 4
//Value: 1 Text: Data: 1
//Value: 8 Text: Data: 8
//Value: 7 Text: Data: 7
//Value: 6 Text: Data: 6
//Value: 9 Text: Data: 9
// CANCELLING...
//Task Complete: 0 : Data: 0
//Task Complete: 2 : Data: 2
//Task Complete: 3 : Data: 3
//Task Complete: 1 : Data: 1
//Task Complete: 5 : Data: 5
//Task Complete: 4 : Data: 4
//Task Complete: 8 : Data: 8
//Task Complete: 6 : Data: 6
//Task Complete: 7 : Data: 7
//Task Complete: 9 : Data: 9..






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 14 at 23:29

























answered Nov 12 at 21:02









Michael Puckett II

3,71841436




3,71841436











  • This is great, thank you...just working my way through it.
    – TrevorBrooks
    Nov 12 at 21:21










  • I have added the structure of my data.
    – TrevorBrooks
    Nov 12 at 23:09










  • Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
    – TrevorBrooks
    Nov 14 at 21:28






  • 1




    Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
    – Michael Puckett II
    Nov 14 at 23:30










  • Thank you. That line actually never gets called. :-/
    – TrevorBrooks
    Nov 15 at 13:56
















  • This is great, thank you...just working my way through it.
    – TrevorBrooks
    Nov 12 at 21:21










  • I have added the structure of my data.
    – TrevorBrooks
    Nov 12 at 23:09










  • Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
    – TrevorBrooks
    Nov 14 at 21:28






  • 1




    Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
    – Michael Puckett II
    Nov 14 at 23:30










  • Thank you. That line actually never gets called. :-/
    – TrevorBrooks
    Nov 15 at 13:56















This is great, thank you...just working my way through it.
– TrevorBrooks
Nov 12 at 21:21




This is great, thank you...just working my way through it.
– TrevorBrooks
Nov 12 at 21:21












I have added the structure of my data.
– TrevorBrooks
Nov 12 at 23:09




I have added the structure of my data.
– TrevorBrooks
Nov 12 at 23:09












Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
– TrevorBrooks
Nov 14 at 21:28




Thank you for your answer it really helped me a lot. I was able to incorporate this into my work. One last question if it's not too difficult, how do I write to the console when each task completes?
– TrevorBrooks
Nov 14 at 21:28




1




1




Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
– Michael Puckett II
Nov 14 at 23:30




Hey @TrevorBrooks I've updated the question with your comment question here at the bottom. Let me know if you have anymore questions and apologies I didn't see the previous ones until now.
– Michael Puckett II
Nov 14 at 23:30












Thank you. That line actually never gets called. :-/
– TrevorBrooks
Nov 15 at 13:56




Thank you. That line actually never gets called. :-/
– TrevorBrooks
Nov 15 at 13:56

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53242770%2ftask-parallel-library-and-long-running-tasks%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Darth Vader #20

How to how show current date and time by default on contact form 7 in WordPress without taking input from user in datetimepicker

Ondo