Playing around with yield and Task.
The following simple example runs fine.
class Program
{
private static void Main(string[] args)
{
string[] messages = { "First task", "Second task", "Third task", "Fourth task" };
var taskList = CreateTaskList(messages).ToList();
taskList.ForEach(task => task.Start());
Task.WaitAll(taskList.ToArray());
Console.WriteLine("Main method complete. Press enter to finish.");
Console.ReadLine();
}
static IEnumerable<Task> CreateTaskList(string[] messages)
{
foreach (var message in messages)
{
yield return new Task(obj => PrintMessage((string)obj!), message);
}
}
static void PrintMessage(object message)
{
Console.WriteLine("Message: {0}", message);
}
}
But the following does not. Is some deadlock at play? Its stuck at Task.WaitAll. So all that I get from Console is Before wait all
class SimpleClass
{
public int Counter { get; set; }
}
class Program
{
private static void Main(string[] args)
{
// create the simple object
var simpleObject = new SimpleClass();
var taskList = CreateTaskEnumerable(simpleObject, 10);
// Start all of the tasks
foreach (var task in taskList)
task.Start();
Console.WriteLine("Before wait all");
// wait for all of the tasks to complete
Task.WaitAll(taskList.ToArray());
Console.WriteLine("After wait all");
foreach (var task in taskList)
simpleObject.Counter += task.Result;
// write out the counter value
Console.WriteLine("Expected value {0}, Counter value: {1}", 10000, simpleObject.Counter);
// wait for input before exiting
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
private static IEnumerable<Task<int>> CreateTaskEnumerable(SimpleClass simpleObject, int numberOfTasks)
{
for (int i = 0; i < numberOfTasks; i++)
{
yield return new Task<int>((stateObject) =>
{
// get the state object
var localCounter = (int)stateObject!;
// enter a loop for 1000 increments
for (int j = 0; j < 1000; j++)
// increment the counters
localCounter++;
return localCounter;
}, simpleObject.Counter);
}
}
}
If I remove yield altogether, the above will be as follows, and works. It gives the output as follows. I am expecting the same output from the above as well, but thats stuck. Why?
Before wait all
After wait all
Expected value 10000, Counter value: 10000
Press enter to finish
The program.
class SimpleClass
{
public int Counter { get; set; }
}
class Program
{
private static void Main(string[] args)
{
// create the bank account instance
var simpleObject = new SimpleClass();
// create an list of tasks
var taskList = new List<Task<int>>();
for (int i = 0; i < 10; i++)
{
// create a new task
var task = new Task<int>((stateObject) =>
{
// get the state object
var localCounter = (int)stateObject!;
// enter a loop for 1000 increments
for (int j = 0; j < 1000; j++)
// increment the counters
localCounter++;
return localCounter;
}, simpleObject.Counter);
taskList.Add(task);
}
// Start all of the tasks
foreach (var task in taskList)
task.Start();
Console.WriteLine("Before wait all");
// wait for all of the tasks to complete
Task.WaitAll(taskList.ToArray());
Console.WriteLine("After wait all");
foreach (var task in taskList)
simpleObject.Counter += task.Result;
// write out the counter value
Console.WriteLine("Expected value {0}, Counter value: {1}", 10000, simpleObject.Counter);
// wait for input before exiting
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}
In the first example you are calling CreateTaskList(messages).ToList() which forces CreateTaskList to yield all tasks before continuing. In the second example you do not call ToList(), and the tasks are yielded in the foreach and then started. The problem is in line Task.WaitAll(taskList.ToArray());. It takes the IEnumerable and yields the tasks again, and you are waiting for them to finish, but they are not started. In other words, every time you call foreach or ToList() on your 'yielded' IEnumerable, it will run the method CreateTaskEnumerable and create new tasks.
One solution is to call var taskList = CreateTaskEnumerable(simpleObject, 10).ToList() or you could just manualy create list in CreateTaskEnumerable and return it.
P.S. I would suggest you read how yield return works, or test it in https://sharplab.io/. It basically creates IEnumerable that gets its data from your method. This means your method will be executed every time your IEnumerable is enumerated.
Related
In UWP,we can fetch the children by FindDescendants<> .But in winui, we can't able to do that.
By doing with visualhelpertree,It always shows zero count in getchildCount() from the calendarview
I just wanted to know how to fetch the children of calendarview .
Also i have tried this but shows me zero child always,
private void FindDescendants1(DependencyObject parent, Type targetType)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
itemchange.Text = childrenCount.ToString();
for (int i = 0; i < childrenCount; i++)
{
var child =(CalendarViewDayItem) VisualTreeHelper.GetChild(parent, i);
if (child.GetType() == targetType)
{
results.Add(child);
}
FindDescendants1(child, targetType);
}
}
Simply I have created this function to get the child and called,
foreach (DependencyObject displayedDay in results)
{
//displayedDay = (CalendarViewDayItem)displayedDay;
CalendarViewDayItem c = displayedDay as CalendarViewDayItem;
if (_highlightedDates.Contains(c.Date))
{
Console.WriteLine(c.Date.ToString());
//highlight
c.Background = new SolidColorBrush(Colors.Red);
}
itemchange.Text = c.Date.ToString();
}
But this not getting the child ,results is the list of objects here where it always show me zero .
My first guess is that you are calling FindDescendants1() before the control is loaded, in the constructor for example. If your CalendarView is in a Page, try calling FindDescendants1() in the Page's Loaded event.
But there's another problem in you code below.
var child = (CalendarViewDayItem)VisualTreeHelper.GetChild(parent, i);
You'll get an exception because you're trying to cast every DependencyObject to a CalendarViewDayItem. By removing the cast you should get the CalendarViewItems. Though, I would make the FinDescendants() static and just receive the results:
private static IEnumerable<T> FindDescendantsOfType<T>(DependencyObject parent) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is T hit)
{
yield return hit;
}
foreach (T? grandChild in FindChildrenOfType<T>(child))
{
yield return grandChild;
}
}
}
And use it like this:
this.results = FindChildrenOfType<CalendarViewDayItem>(this.CalendarViewControl);
foreach (var item in this.results)
{
// Do you work here...
}
Lets say I have a list of asteroid objects like so:
9_Amphitrite
24_Themis
259_Aletheia
31_Euphrosyne
511_Davida
87_Sylvia
9_Metis
41_Daphne
Each asteroid has a title, a StartRoationPeriod, and a EndRoationPeriod.
I need to concatenate their names based on how close the current asteroid StartRoationPeriod and previous asteroid EndRoationPeriod are to an orbital constant and then spit out the concatenated title.
So with the above list, the final objects may look like this:
9_Amphitrite
24_Themis;259_Aletheia
31_Euphrosyne;511_Davida;87_Sylvia
9_Metis
41_Daphne
This requires me to keep track of both the current and previous asteroids.
I started to write the loop, but I'm unsure of where or even how to check the current asteroids start rotation period against the previous asteroids end rotation period...basically, it just gets messy fast...
string asteroid_title = string.Empty;
Asteroid prev_asteroid = null;
foreach (var asteroid in SolarSystem)
{
if (prev_asteroid != null)
{
if (asteroid.StartRoationPeriod + OrbitalConstant >= prev_asteroid.EndRoationPeriod)
{
asteroid_title = asteroid_title + asteroid.Title;
} else {
asteroid_title = asteroid.Title;
yield return CreateTitle();
}
}
prev_evt = evt;
}
I think this should work for you (If aggregate looks too complex try to convert it to a foreach,it's easy)
using System;
using System.Collections.Generic;
using System.Linq;
namespace Program
{
class Asteroid
{
public int EndRoationPeriod { get; internal set; }
public string Name { get; internal set; }
public int StartRoationPeriod { get; internal set; }
}
class AsteroidGroup
{
public int EndRoationPeriod { get; internal set; }
public string Names { get; internal set; }
}
internal class Program
{
private static void Main(string[] args)
{
int OrbitalConstant = 10;
List<Asteroid> SolarSystem = new List<Asteroid>()
{
new Asteroid() { Name= "9_Amphitrite" ,StartRoationPeriod=10 ,EndRoationPeriod=50},
new Asteroid() { Name= "24_Themis" ,StartRoationPeriod=45,EndRoationPeriod=100},
new Asteroid() { Name= "259_Aletheia",StartRoationPeriod=40 ,EndRoationPeriod=150},
new Asteroid() { Name= "31_Euphrosyne" ,StartRoationPeriod=60,EndRoationPeriod=200},
new Asteroid() { Name= "511_Davida" ,StartRoationPeriod=195,EndRoationPeriod=250},
new Asteroid() { Name= "87_Sylvia" ,StartRoationPeriod=90,EndRoationPeriod=300},
new Asteroid() { Name= "9_Metis" ,StartRoationPeriod=100,EndRoationPeriod=350},
new Asteroid() { Name= "41_Daphne" ,StartRoationPeriod=110,EndRoationPeriod=400},
};
var result = //I skip the first element because I initialize a new list with that element in the next step
SolarSystem.Skip(1)
//The first argument of Aggregate is a new List with your first element
.Aggregate(new List<AsteroidGroup>() { new AsteroidGroup { Names = SolarSystem[0].Name, EndRoationPeriod = SolarSystem[0].EndRoationPeriod } },
//foreach item in your list this method is called,l=your list and a=the current element
//the method must return a list
(l, a) =>
{
//Now this is your algorithm
//Should be easy to undrestand
var last = l.LastOrDefault();
if (a.StartRoationPeriod + OrbitalConstant >= last.EndRoationPeriod)
{
last.Names += " " + a.Name;
last.EndRoationPeriod = a.EndRoationPeriod;
}
else
l.Add(new AsteroidGroup { Names = a.Name, EndRoationPeriod = a.EndRoationPeriod });
//Return the updated list so it can be used in the next iteration
return l;
});
A more compact solution
var result = SolarSystem
.Skip(1)
.Aggregate( SolarSystem.Take(1).ToList(),
(l, a) => (a.StartRoationPeriod + OrbitalConstant >= l[l.Count - 1].EndRoationPeriod) ?
(l.Take(l.Count - 1)).Concat(new List<Asteroid> { new Asteroid() { Name = l[l.Count - 1].Name += " " + a.Name, EndRoationPeriod = a.EndRoationPeriod } }).ToList() :
l.Concat(new List<Asteroid> { a }).ToList()
);
My program has 3 functions. Each function takes a list of Items and fill certain information.
For example
class Item {
String sku,upc,competitorName;
double price;
}
function F1 takes a List and fills upc
function F2 takes List (output of F1) and fills price.
function F3 takes List (output of F2) and fills competitorName
F1 can process 5 items at a time,
F2 can process 20 items at a time,
F3 also 20.
Right now I am running F1 -> F2 -> F3 in serial because F2 needs info(UPC code) from F1. F3 needs price from F2.
I would like to make this process efficient by running F1 run continuously instead of waiting for F2 and F3 to be completed. F1 executes and output into queue then F2 takes 20 items at a time and process them. and then follows F3.
How can i achieve this by using BlockingCollection and Queue?
This is a typical use case of Apache Storm in case you've continuous items coming in to F1. You can implement this in Storm in matter of minutes and you'll have fast and perfectly parallel system in place. Your F1, F2 and F3 will become bolts and your Items producer will become spout.
Since you asked how to do it using BlockingCollections here is an implementation. You'll need 3 threads in total.
ItemsProducer: It is producing 5 items at a time and feeding it to F1.
F2ExecutorThread: It is consuming 20 items at a time and feeding it to F2.
F3ExecutorThread: It is consuming 20 items at a time and feeding it to F3.
You also have 2 blocking queues one is used to transfer data from F1->F2 and one from F2->F3. You can also have a queue to feed data to F1 in similar fashion if required. It depends upon how you are getting the items. I've used Thread.sleep to simulate the time required to execute the function.
Each function will keep looking for items in their assigned queue, irrespective of what other functions are doing and wait until the queue has items. Once they've processed the item they'll put it in another queue for another function. They'll wait until the other queue has space if it is full.
Since all your functions are running in different threads, F1 won't be waiting for F2 or F3 to finish. If your F2 and F3 are significantly faster then F1 you can assign more threads to F1 and keep pushing to same f2Queue.
public class App {
final BlockingQueue<Item> f2Queue = new ArrayBlockingQueue<>(100);
final BlockingQueue<Item> f3Queue = new ArrayBlockingQueue<>(100);
public static void main(String[] args) throws InterruptedException {
App app = new App();
app.start();
}
public void start() throws InterruptedException {
Thread t1 = new ItemsProducer(f2Queue);
Thread t2 = new F2ExecutorThread(f2Queue, f3Queue);
Thread t3 = new F3ExecutorThread(f3Queue);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
}
}
/**
* Thread producing 5 items at a time and feeding it to f1()
*/
class ItemsProducer extends Thread {
private BlockingQueue<Item> f2Queue;
private static final int F1_BATCH_SIZE = 5;
public ItemsProducer(BlockingQueue<Item> f2Queue) {
this.f2Queue = f2Queue;
}
public void run() {
Random random = new Random();
while (true) {
try {
List<Item> items = new ArrayList<>();
for (int i = 0; i < F1_BATCH_SIZE; i++) {
Item item = new Item(String.valueOf(random.nextInt(100)));
Thread.sleep(20);
items.add(item);
System.out.println("Item produced: " + item);
}
// Feed items to f1
f1(items);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void f1(List<Item> items) throws InterruptedException {
Random random = new Random();
for (Item item : items) {
Thread.sleep(100);
item.upc = String.valueOf(random.nextInt(100));
f2Queue.put(item);
}
}
}
/**
* Thread consuming items produced by f1(). It takes 20 items at a time, but if they are not
* available it waits and starts processesing as soon as one gets available
*/
class F2ExecutorThread extends Thread {
static final int F2_BATCH_SIZE = 20;
private BlockingQueue<Item> f2Queue;
private BlockingQueue<Item> f3Queue;
public F2ExecutorThread(BlockingQueue<Item> f2Queue, BlockingQueue<Item> f3Queue) {
this.f2Queue = f2Queue;
this.f3Queue = f3Queue;
}
public void run() {
try {
List<Item> items = new ArrayList<>();
while (true) {
items.clear();
if (f2Queue.drainTo(items, F2_BATCH_SIZE) == 0) {
items.add(f2Queue.take());
}
f2(items);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
void f2(List<Item> items) throws InterruptedException {
Random random = new Random();
for (Item item : items) {
Thread.sleep(100);
item.price = random.nextInt(100);
f3Queue.put(item);
}
}
}
/**
* Thread consuming items produced by f2(). It takes 20 items at a time, but if they are not
* available it waits and starts processesing as soon as one gets available.
*/
class F3ExecutorThread extends Thread {
static final int F3_BATCH_SIZE = 20;
private BlockingQueue<Item> f3Queue;
public F3ExecutorThread(BlockingQueue<Item> f3Queue) {
this.f3Queue = f3Queue;
}
public void run() {
try {
List<Item> items = new ArrayList<>();
while (true) {
items.clear();
if (f3Queue.drainTo(items, F3_BATCH_SIZE) == 0) {
items.add(f3Queue.take());
}
f3(items);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void f3(List<Item> items) throws InterruptedException {
Random random = new Random();
for (Item item : items) {
Thread.sleep(100);
item.competitorName = String.valueOf(random.nextInt(100));
System.out.println("Item done: " + item);
}
}
}
class Item {
String sku, upc, competitorName;
double price;
public Item(String sku) {
this.sku = sku;
}
public String toString() {
return "sku: " + sku + " upc: " + upc + " price: " + price + " compName: " + competitorName;
}
}
I guess you can follow the exact same approach in .Net as well. For better understanding I suggest you to go through basic architecture of http://storm.apache.org/releases/current/Tutorial.html
I tried to do same thing in .NET and i think it is working.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace BlockingCollectionExample
{
class Program
{
static void Main(string[] args)
{
BlockingCollection<Listing> needUPCJobs = new BlockingCollection<Listing>();
BlockingCollection<Listing> needPricingJobs = new BlockingCollection<Listing>();
// This will have final output
List<Listing> output = new List<Listing>();
// start executor 1 which waits for data until available
var executor1 = Task.Factory.StartNew(() =>
{
int maxSimutenousLimit = 5;
int gg = 0;
while (true)
{
while (needUPCJobs.Count >= maxSimutenousLimit)
{
List<Listing> tempListings = new List<Listing>();
for (int i = 0; i < maxSimutenousLimit; i++)
{
Listing listing = new Listing();
if (needUPCJobs.TryTake(out listing))
tempListings.Add(listing);
}
// Simulating some delay for first executor
Thread.Sleep(1000);
foreach (var eachId in tempListings)
{
eachId.UPC = gg.ToString();
gg++;
needPricingJobs.Add(eachId);
}
}
if (needUPCJobs.IsAddingCompleted)
{
if (needUPCJobs.Count == 0)
break;
else
maxSimutenousLimit = needUPCJobs.Count;
}
}
needPricingJobs.CompleteAdding();
});
// start executor 2 which waits for data until available
var executor2 = Task.Factory.StartNew(() =>
{
int maxSimutenousLimit = 10;
int gg = 10;
while (true)
{
while (needPricingJobs.Count >= maxSimutenousLimit)
{
List<Listing> tempListings = new List<Listing>();
for (int i = 0; i < maxSimutenousLimit; i++)
{
Listing listing = new Listing();
if (needPricingJobs.TryTake(out listing))
tempListings.Add(listing);
}
// Simulating more delay for second executor
Thread.Sleep(10000);
foreach (var eachId in tempListings)
{
eachId.Price = gg;
gg++;
output.Add(eachId);
}
}
if (needPricingJobs.IsAddingCompleted)
{
if(needPricingJobs.Count==0)
break;
else
maxSimutenousLimit = needPricingJobs.Count;
}
}
});
// producer thread
var producer = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 100; i++)
{
needUPCJobs.Add(new Listing() { ID = i });
}
needUPCJobs.CompleteAdding();
});
// wait for producer to finish producing
producer.Wait();
// wait for all executors to finish executing
Task.WaitAll(executor1, executor2);
Console.WriteLine();
Console.WriteLine();
}
}
public class Listing
{
public int ID;
public string UPC;
public double Price;
public Listing() { }
}
}
I want to prove that re-using instances of OrganizationServiceProxy between threads will cause problems.
This console app does not have a problem re-using the same instance of OrganizationServiceProxy between threads:
class Program
{
private static OrganizationServiceProxy Service { get; set; }
static void Main(string[] args)
{
Connect(); // Initializes Service
for (int i = 0; i < 100; i++)
{
int index = i;
Task.Run(() =>
{
for (int i2 = 0; i2 < 10; i2++)
{
try
{
Console.WriteLine("Creating" + index);
Entity record = new Entity("account");
record.Id = new Guid("4986e130-45f7-e411-9454-00155d91de01");
record["name"] = index + " - " + i2;
Service.Update(record);
Console.WriteLine("Created" + index);
}
catch (Exception e)
{ }
}
});
}
Console.ReadLine(); // the name of the record ends up as 99 - 9, which is right
}
/* Initialize Service */
private static bool Connect()
{
try
{
ClientCredentials cred = new ClientCredentials();
cred.UserName.UserName = #"r";
cred.UserName.Password = #"";
IServiceManagement<IOrganizationService> serviceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(#"/XRMServices/2011/Organization.svc"));
Service = new OrganizationServiceProxy(serviceManagement, cred);
var who = new Microsoft.Crm.Sdk.Messages.WhoAmIRequest(); // used to test the connection
var whoResponse = (Microsoft.Crm.Sdk.Messages.WhoAmIResponse)Service.Execute(who); // this fails if not connected
}
catch (Exception e)
{
Console.WriteLine("Connecting to CRM.\n" + e.Message + ((e.InnerException != null) ? "\n" + e.InnerException.Message : ""));
return false;
}
return true;
}
}
The SDK states that any instance members of OrganizationServiceProxy are not guaranteed to be thread safe.
How can I cause a problem with an OrganizationServiceProxy shared between threads?
What kinds of problem are to be expected?
I'm not sure I know the specific answer to your question, but something that is marked as not guaranteed of being thread-safe just means exactly that: It may be safe, but the author has not tested for it or specifically written any thread-safe code for those classes, and thus cannot guarantee thread safety.
I do know that thread-safety definitely comes into play with Plugins on the server. This is why you are not supposed to use local fields in a Plugin class. The Plugin engine re-uses the instances of your Plugin class instead of re-instantiating them for each execution. This means it is possible that your Plugin could execute with "old data" in those local fields that was used by the last thread, which could obviously cause all kinds of problems.
I want to write an algorithm to sequentially press keys F1-F3. My form has these controls:
lblF1
textboxF1
lblF2
textboxF2
lblF3
textboxF3
btnStart
In textboxF1-textboxF3 the time in seconds is entered. This when the program is to press the hotkey. It is important that the program can't press two keys at once, for example F1 and F2. It may not press more than one key in a second. When I click on btnStart it calls Run().
This is how I tried to resolve this:
static int counterF1 = 9999;
static int counterF2 = 9999;
static int counterF3 = 9999;
public void Run()
{
counterF1 = 9999;
counterF2 = 9999;
counterF3 = 9999;
while (true)
{
Loop();
}
}
public void Loop()
{
bool used = false;
if (counterF1 >= (int)textboxF1.text)
{
counterF1 = PressKey(VK_F1);
used = true;
}
if (counterF2 >= (int)textboxF2.text)
{
counterF2 = PressKey(VK_F2);
used = true;
}
if (counterF3 >= (int)textboxF3.text)
{
counterF3 = PressKey(VK_F3);
used = true;
}
if (used == false)
{
IncrementCounters();
Delay(1000);
}
}
public double PressKey(uint key)
{
myPostMessageA(hWindow, WM_KEYDOWN, (uint)key, (uint)key);
IncrementCounters();
return 1; //return 1 because one second
}
public void IncrementCounters()
{
counterF1++;
counterF2++;
counterF3++;
}
But often it doesn't press any key (it is possible it is too late, but can't be an omission). Can you explain how to make an algorithm for this?
We will use a class KeyStroke that stores the necessary data for a special key:
public class KeyStroke
{
public int period { get; set; } // Period in which to hit key
public int next { get; set; } // ticks to the next hit of this key
public int VK { get; set; } //KeyCode
}
public List<KeyStroke> keys = new List<KeyStroke>();
An Initialize() method is needed to read the data from the text boxes and to init the simulation. We utilize a timer with the interval of one second to run the simulation. In my example, I don't read from textboxes, but use constant values. Add the input and error handling. If you use WPF, you can bind the KeyStroke objects to the textboxes.
void Init()
{
//Initialize keys with according periods from input
keys.Clear();
keys.Add(new KeyStroke() { VK = VK_F1, period = 1, next = 1 });
keys.Add(new KeyStroke() { VK = VK_F2, period = 10, next = 10 });
keys.Add(new KeyStroke() { VK = VK_F3, period = 5, next = 5 });
//sort keys by period (descending), in order to handle long period keys, too
keys.Sort((first, second) => second.period.CompareTo(first.period));
//Start the program
var t = new DispatcherTimer();
t.Interval = TimeSpan.FromSeconds(1);
t.Tick += new EventHandler(t_Tick);
t.Start();
}
The tick event is similar to yours:
void t_Tick(object sender, EventArgs e)
{
bool used = false;
foreach (var key in keys)
{
if (key.next <= 0 && !used)
{
PressKey(key.VK);
key.next = key.period;
used = true;
}
key.next--;
}
}