I'm trying to optimize a small program. So here is the basic idea:
I have an array of unfiltered data, and I wanna pass that to a function which will call another function, twice, for data filtering and insertion to a new list. The first call will take the data from original array in range from 0 => half of arrays length, and the second will do the same, but with range from half, to the last item. This way, I should make simultaneous insertion of filtered data into the same list. After the insertion is completed the filtered list can be passed to the rest of the program. Here's the code:
static void Main(string[]
{
// the unfiltered list
int[] oldArray = new int[6] {1,2,3,4,5,6};
// filtered list
List<int> newList= new List<int>();
// Functions is my static class
Functions.Insert(newList, oldArray )
Continue_Program_With_Filtered_List(newList);
// remaining functions...
}
And here is the Function class:
public static class Functions
{
public static void Insert(List<int> newList, int[] oldArray)
{
new Thread(() =>
{
Inserter(newList, oldArray, true);
}).Start();
new Thread(() =>
{
Inserter(newList, oldArray, false);
}).Start();
// I need to wait the result here of both threads
// and make sure that every item from oldArray has been filtered
// before I proceed to the next function in Main()
}
public static void Inserter(List<int> newList, int[] oldArray, bool countUp)
{
bool filterIsValid = false;
int length = oldArray.Length;
int halflen = (int)Math.Floor((decimal)length / 2);
if (countUp)
{
// from half length to 0
for (int i = 0; i < halflen; i++)
{
// filtering conditions here to set value of filterIsValid
if(filterIsValid)
newList.Add(oldArray[i]);
}
}
else
{
// from half length to full length
for (int i = halflen + 1; i < length; i++)
{
// filtering conditions here to set value of filterIsValid
if(filterIsValid)
newList.Add(oldArray[i]);
}
}
}
}
So the problem is that I must await Function.Insert() to complete every thread, and pass through every item before the newList is passed to the next function in Main().
I've no idea how to use Tasks or async method on something like this. This is just an outline of the program by the way. Any help?
In your case using PLINQ may also an option.
static void Main(string[] args)
{
// the unfiltered list
int[] oldArray = new int[6] { 1, 2, 3, 4, 5, 6 };
// filtered list
List<int> newList = oldArray.AsParallel().Where(filter).ToList();
// remaining functions...
}
You can also use AsOrdered() to preserve order
To come back to your initial question, here's what you can do
Note: Solution with minimal changes to your original code, whether there are other possible optimizations or not
Additional Note: Keep in mind that there can still be concurrency issues depending on what else you do with the arguments passing to that function.
public static async Task Insert(List<int> newList, int[] oldArray)
{
ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
var task1 = Task.Factory.StartNew(() =>
{
Inserter(concurrentBag, oldArray, true);
});
var task2 = Task.Factory.StartNew(() =>
{
Inserter(concurrentBag, oldArray, false);
});
await Task.WhenAll(task1, task2);
newList.AddRange(concurrentBag);
}
public static void Inserter(ConcurrentBag<int> newList, int[] oldArray, bool countUp)
{
//Same code
}
Edit: Your second for-loop is wrong, change it to this or you will loose one item
for (int i = halflen; i < length; i++)
Related
I'm learning the usage of async and await, and tried to do the following:
I have an array of numbers in a particular order, and an async method that gets a number and a time delay, and return the same passed-in number.
What I'd like to achieve is to print the numbers in a reveresed order (relative to the calling order), utilizing the time delay.
I'm having a hard time figuring out how to do it, and be glad for a guidance. Here's what I have (which, ofcourse, doesn't work):
public static async Task<int> DelayAndReturn(int number, int milisecDelay)
{
await Task.Delay(milisecDelay);
return number;
}
public static void Main(string[] args)
{
int[] arr = { 1, 2, 3 };
int milisecDelay = 10000;
foreach (int num in arr)
{
Console.WriteLine(DelayAndReturn(num, milisecDelay));
milisecDelay /= 10;
}
Console.ReadLine();
}
DelayAndReturn returns a Task object and the correct way to get the result of that object is to await the task. However, awaiting the task will also stop your foreach until 10000 ms have passed, and only then send the next item for processing.
Note that, although the code execution is waiting for the asynchronous operation to complete, the thread is free to be used by other processes.
Your best bet to get them printed in reversed order, is to create a collection of tasks and await all of them.
public static async Task DelayAndReturn(int number, int milisecDelay)
{
await Task.Delay(milisecDelay);
Console.WriteLine(number);
}
public static void Main(string[] args)
{
PrintReversed().GetAwaiter().GetResult();
}
public static async Task PrintReversed() {
int[] arr = { 1, 2, 3 };
int milisecDelay = 1000;
List<Task> tasks = new List<Task>();
foreach (int num in arr)
{
tasks.Add(DelayAndReturn(num, milisecDelay));
milisecDelay /= 10;
}
await Task.WhenAll(tasks);
}
I have a multi-line textbox and I want to process each line with multi threads.
The textbox could have a lot of lines (1000+), but not as many threads. I want to use custom amount of threads to read all those 1000+ lines without any duplicates (as in each thread reading UNIQUE lines only, if a line has been read by other thread, not to read it again).
What I have right now:
private void button5_Click(object sender, EventArgs e)
{
for (int i = 0; i < threadCount; i++)
{
new Thread(new ThreadStart(threadJob)).Start();
}
}
private void threadJob()
{
for (int i = 0; i < txtSearchTerms.Lines.Length; i++)
{
lock (threadLock)
{
Console.WriteLine(txtSearchTerms.Lines[i]);
}
}
}
It does start the correct amount of threads, but they all read the same variable multiple times.
Separate data collection and data processing and next possible steps after calculation. You can safely collect results calculated in parallel by using ConcurrentBag<T>, which is simply thread-safe collection.
Then you don't need to worry about "locking" objects and all lines will be "processed" only once.
1. Collect data
2. Execute collected data in parallel
3. Handle calculated result
private string Process(string line)
{
// Your logic for given line
}
private void Button_Click(object sender, EventArgs e)
{
var results = new ConcurrentBag<string>();
Parallel.ForEach(txtSearchTerms.Lines,
line =>
{
var result = Process(line);
results.Add(result);
});
foreach (var result in results)
{
Console.WriteLine(result);
}
}
By default Parallel.ForEach will use as much threads as underlying scheduler provides.
You can control amount of used threads by passing instance of ParallelOptions to the Parallel.ForEach method.
var options = new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
var results = new ConcurrentBag<string>();
Parallel.ForEach(values,
options,
value =>
{
var result = Process(value);
results.Add(result);
});
Consider using Parallel.ForEach to iterate over the Lines array. It is just like a normal foreach loop (i.e. each value will be processed only once), but the work is done in parallel - with multiple Tasks (threads).
var data = txtSearchTerms.Lines;
var threadCount = 4; // or whatever you want
Parallel.ForEach(data,
new ParallelOptions() { MaxDegreeOfParallelism = threadCount },
(val) =>
{
//Your code here
Console.WriteLine(val);
});
The above code will need this line to be added at the top of your file:
using System.Threading.Tasks;
Alternatively if you want to not just execute something, but also return / project something then instead try:
var results = data.AsParallel(new ParallelLinqOptions()
{
MaxDegreeOfParallelism = threadCount
}).Select(val =>
{
// Your code here, I just return the value but you could return whatever you want
return val;
}).ToList();
which still executes the code in parallel, but also returns a List (in this case with the same values in the original TextBox). And most importantly, the List will be in the same order as your input.
There many ways to do it what you want.
Take an extra class field:
private int _counter;
Use it instead of loop index. Increment it inside the lock:
private void threadJob()
{
while (true)
{
lock (threadLock)
{
if (_counter >= txtSearchTerms.Lines.Length)
return;
Console.WriteLine(txtSearchTerms.Lines[_counter]);
_counter++;
}
}
}
It works, but it very inefficient.
Lets consider another way. Each thread will handle its part of the dataset independently from the others.
public void button5_Click(object sender, EventArgs e)
{
for (int i = 0; i < threadCount; i++)
{
new Thread(new ParameterizedThreadStart(threadJob)).Start(i);
}
}
private void threadJob(object o)
{
int threadNumber = (int)o;
int count = txtSearchTerms.Lines.Length / threadCount;
int start = threadNumber * count;
int end = threadNumber != threadCount - 1 ? start + count : txtSearchTerms.Lines.Length;
for (int i = start; i < end; i++)
{
Console.WriteLine(txtSearchTerms.Lines[i]);
}
}
This is more efficient because threads do not wait on the lock. However, the array elements are processed not in a general manner.
I have this function that call itself to find all the possible combination with the array of int. The problem is that the program calculate the first combination and then, when the recursion continues, the List of combination still contains that value and i don't understand why.
public static void Permutation(List<int> items, int h, List<int> actualCombination)
{
if (h == actualCombination.Count)
{
results[results.Count] = actualCombination;
}
else
{
for (int i = 0; i < items.Count; i++)
{
actualCombination.Add(items[i]);
List<int> temp = new List<int>(items);
temp.Remove(items[i]);
Permutation(temp, h, actualCombination);
}
return;
}
}
after that, i call the function in main. In my case the second parameter specify the combination length."Results" is a Dictionary composed by int as key and List as value that is used to save all the combination.
static void Main(string[] args)
{
Permutation(new List<int> { 1, 2, 3 }, 3, new List<int>());
Console.ReadKey();
}
I solved the problem by copying the List before of the function add.
I want to fill a collection until any of these two conditions is satisfied:
either allowed time of 5 seconds has completed, or
collection reached the count of 5 items.
If any of these conditions is fulfilled, the method that i subscribed to should be executed (in this case Console.WriteLine)
static void Main(string[] args)
{
var sourceCollection = Source().ToObservable();
var bufferedCollection = sourceCollection.Buffer(
() => Observable.Amb(
Observable.Timer(TimeSpan.FromSeconds(5)//,
//Observable.TakeWhile(bufferedCollection, a=> a.Count < 5)
))
);
bufferedCollection.Subscribe(col =>
{
Console.WriteLine("count of items is now {0}", col.Count);
});
Console.ReadLine();
}
static IEnumerable<int> Source()
{
var random = new Random();
var lst = new List<int> { 1,2,3,4,5 };
while(true)
{
yield return lst[random.Next(lst.Count)];
Thread.Sleep(random.Next(0, 1500));
}
}
i managed to make it work with the Observable.Timer, but the TakeWhile doesnt work, how do I check for the collection count, does TakeWhile work for this or is there some other method? Im sure its something simple.
I got it, the answer was in the documentation of Buffer - there's an overload that takes a parameter that specifies the maximum count. So I don't need Observable.Amb, I can just say
var sourceCollection = Source().ToObservable();
var maxBufferCount = 5;
var bufferedCollection = sourceCollection.Buffer(TimeSpan.FromSeconds(5), maxBufferCount, Scheduler.Default);
bufferedCollection.Subscribe(col =>
{
Console.WriteLine("count of items is now {0}", col.Count);
});
Console.ReadLine();
I am trying to develop an optimization function that will determine which elements in list of doubles when added together will be less than a specified threshold values. The elements can be used multiple times.
For example if my list of elements is
{1,3,7,10}
and my threshold is 20 I would expect my result to be
1
3
7
10
10, 10
10, 7
10, 7, 3
10,7,1
10,7,1,1
10,7,1,1,1
7,7
7,7,3
7,7,1
7,7,1,1
7,7,1,1,1
...
I expect that the answer to this question will probably be a recursive call and probably could be found in a textbook, but I don't know how to properly phrase the question to find the answer. Help from this group of experts would be appreciated.
This program works, and seems to be the simplest solution. All results are sorted ascending.
private static final HashSet<ArrayList<Double>> lists =
new HashSet<ArrayList<Double>>(); // all of the combinations generated
private static final double[] elements = {10, 7, 3, 1};
public static void main(String[] args) {
combine(20, new ArrayList<Double>());
for (ArrayList<Double> set : lists) {
System.out.println(set);
}
}
private static void combine(final double limit, ArrayList<Double> stack) {
// iterates through the elements that fit in the threshold
for (double item : elements) {
if (item < limit) {
final ArrayList<Double> nextStack = new ArrayList<Double>(stack);
nextStack.add(item);
// a sort is necessary to let the HashSet de-dup properly
Collections.sort(nextStack);
lists.add(nextStack);
combine(limit - item, nextStack);
}
}
}
This type of combinatoric problem, though, generates many results. If you are more concerned with performance than code readability and simplicity, I can optimize further.
c#:
static void Main(string[] args)
{
Run();
}
static public void Run()
{
Combine(20, new List<Double>());
foreach (List<Double> set in lists)
{
Debug.Print(set.ToString());
}
}
private static HashSet<List<Double>> lists =
new HashSet<List<Double>>(); // all of the combinations generated
private static double[] elements = { 10, 7, 3, 1 };
private static void Combine(double limit, List<Double> stack)
{
// iterates through the elements that fit in the threshold
foreach (double item in elements)
{
if (item < limit)
{
List<Double> nextStack = new List<Double>(stack);
nextStack.Add(item);
// a sort is necessary to let the HashSet de-dup properly
nextStack.Sort();
lists.Add(nextStack);
Combine(limit - item, nextStack);
}
}
}
I'm not sure if the Sort() is needed for detecting correctly duplicate entries but this code should work:
private List<int[]> CombinedElementsInArrayLessThanValue(int[] foo, int value)
{
List<int[]> list = new List<int[]>();
for (int i = 0; i < foo.Length; i++)
{
List<int> start = new List<int>();
start.Add(foo[i]);
start.Sort();
int[] clone = start.ToArray();
if (start.Sum() < value && !list.Contains(clone))
{
list.Add(clone);
CombinedElementsInArrayLessThanValue(foo, value, start, list);
}
}
return list;
}
private void CombinedElementsInArrayLessThanValue(int[] foo, int value, List<int> partial, List<int[]> accumulate_result)
{
for (int i = 0; i < foo.Length; i++)
{
List<int> clone = new List<int>(partial);
clone.Add(foo[i]);
clone.Sort();
int[] array = clone.ToArray();
if (clone.Sum() < value && !accumulate_result.Contains(array))
{
accumulate_result.Add(array);
CombinedElementsInArrayLessThanValue(foo, value, clone, accumulate_result);
}
}
}
Process one item in the list at a time, and let the recursion handle one item completely in order to shorten the "depth" of the recursion.
public static List<int[]> Combine(int[] elements, int maxValue)
{
LinkedList<int[]> result = new LinkedList<int[]>();
List<int> listElements = new List<int>(elements);
listElements.Sort();
Combine(listElements.ToArray(), maxValue, new int[0], result);
return result.ToList();
}
private static void Combine(int[] elements, int maxValue, int[] stack, LinkedList<int[]> result)
{
if(elements.Length > 0 && maxValue >= elements[0])
{
var newElements = elements.Skip(1).ToArray();
for (int i = maxValue / elements[0]; i > 0; i--)
{
result.AddLast(stack.Concat(Enumerable.Repeat(elements[0], i)).ToArray());
Combine(newElements, maxValue - i*elements[0], result.Last(), result);
}
Combine(newElements, maxValue, stack, result);
}
}