I'm Learning Reactive Extentions, these days I come across this situation, codes here:
class Program
{
private static void Main(string[] args)
{
var ls = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.ToObservable();
ls.Select(m => new
{
t = Observable.Start(() =>
{
Thread.Sleep(100);
return new Random().Next(3, 20);
}),
i = m
}).Subscribe(item => item.t.Subscribe(Console.WriteLine));
Task.WaitAll();
Console.WriteLine("all done");
Console.ReadKey();
}
}
It shows that there is an IObservable in an Observable, and I want to print "all done" after all process done, but this didn't work. "all done" print very quickly as soon as the program start, not wait anymore, in my situation here, what should I do to get a REAL WaitAll?
That is not really how Rx works. There is no link here between Task.WaitAll() and your Rx code. You dont even pass any tasks to the WaitAll() method ;-)
So firstly, the Subscribe method is non-blocking. It just states that at this point I want to start consuming this sequence, and this is what to do when value/error/completion notifications are send to me.
Your nested Observable sequence is a fairly advanced topic to jump straight into, but that is ok we can work with that.
class Program
{
private static void Main(string[] args)
{
//Let go, we are not IEnumerable any more :-)
var ls = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.ToObservable();
var subscription = ls.Select(_ =>
Observable.Start(() =>
{
Thread.Sleep(100);
return new Random().Next(3, 20);
})
})
.Merge() //Merge the IO<IO<T>> into Io<T> so we get a single completion.
.Subscribe(
item => item.Subscribe(Console.WriteLine),
()=>Console.WriteLine("all done"));
Console.ReadKey();
subscription.Dispose();
}
}
You could further improve the code by replacing the Observable.Start + Thread.Sleep with an Rx method likeObservable.Timer or a Scheduler.
The key thing to take away here is that Rx is Async. The point is NOT to block. The only things in this code that are blocking are the Thread.Sleep and the Console.ReadKey(). Ideally as noted above you would replace the Thread.Sleep anyway.
You seem to be doing a bit of "non-Rx" kind of coding here. The task you're trying to perform is actually quite straight forward.
First up, you have some code that produces values after doing some work. I've recoded it as this:
var rnd = new Random();
Func<int> produceValue = () =>
{
Thread.Sleep(100);
return rnd.Next(3, 20);
};
This keeps it nice a separate from the Rx code. As a side note, I've pulled the new Random() declaration outside of the function as it isn't correct to keep instantiating a new Random instance - you won't necessarily get random numbers that way. You should also instantiate once and use the same instance.
So now the code to produce the observable is straight forward:
var query =
from n in Observable.Range(1, 9)
from m in Observable.Start(produceValue)
select m;
And subscribing to it is also easy:
query.Subscribe(
Console.WriteLine,
() => Console.WriteLine("All Done."));
I think that does exactly what you were trying to code for without any nasty WaitFor code.
Related
I am wondering why my Observable does not produce any element when i am not awaiting its source which is an IAsyncEnumerable.I am using a Select over the Observable, and nothing comes out of it , my code does not execute.
public async IAsyncEnumerable<int> GetAsyncEnumerable()
{
int i=0;
while(true)
{
await Task.Delay(1000);
yield return i++;
}
}
public async Task Run()
{
IAsyncEnumerable<int> enumerable=GetAsyncEnumerable().ToObservable();
await foreach(var elem in enumerable)
{
Console.WriteLine(elem);
}
}
In the above example , the code works and is called while below there is nothing coming out.
public async Task RunObs()
{
IAsyncEnumerable<int> enumerable=GetAsyncEnumerable().ToObservable();
IObservable<int> inputObs = enumerable.ToObservable();
var outputObs = inputObs
.Select(elem=>
{
Console.WriteLine(elem); //does not execute
return elem;
});
}
Do I need to store somewhere the reference to this observable, or how should one do this?
The observable does not produce any elements, because you need to subscribe to it to it to get them.
When you await an observable you implicitly subscribe to the observable, the method will return when the observable completes or errors. If it completes you will receive the last value produced.
var outputObs = await GetAsyncEnumerable()
.ToObservable()
.Select(elem =>
{
Console.WriteLine(elem);
return elem;
})
.Take(5);
Console.WriteLine(outputObs);
will output
0, 1, 2, 3, 4, 4 on the console(each number on different lines of course)
This will also cause the observable to produce output:
GetAsyncEnumerable()
.ToObservable()
.Take(5)
.Subscribe(elem =>
{
Console.WriteLine(elem);
});
0, 1, 2, 3, 4
Because now you also subsribed to the observable.
Hope it makes sense?
I am using Atom10FeedFormatter class for processing atom xml feeds calling OData Rest API endpoint.
It works fine, but the api gives the result slow, if there are more than 200 entries in the feed.
That is what I use:
Atom10FeedFormatter formatter = new Atom10FeedFormatter();
XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
string odataurl= "http://{mysite}/_api/ProjectData/Projects";
using (XmlReader reader = XmlReader.Create(odataurl))
{
formatter.ReadFrom(reader);
}
foreach (SyndicationItem item in formatter.Feed.Items)
{
//processing the result
}
I want to speed up this process at least a little faster by splitting the original request to query the results skipping some entries and limiting entry size.
The main idea is count the number of feeds using $count, divide the feed results into blocks of 20, use the $skip and $top in the endpoint url, iterate through the results, and finally summarize them.
int countoffeeds = 500; // for the sake of simplicity, of course, i get it from the odataurl using $count
int numberofblocks = (countoffeeds/20) + 1;
for(int i = 0; i++; i<numberofblocks){
int skip = i*20;
int top = 20;
string odataurl = "http://{mysite}/_api/ProjectData/Projects"+"?&$skip="+skip+"&top=20";
Atom10FeedFormatter formatter = new Atom10FeedFormatter();
using (XmlReader reader = XmlReader.Create(odataurl))
{
formatter.ReadFrom(reader); // And this the part where I am stuck. It returns a void so I
//cannot use Task<void> and process the result later with await
}
...
Normally I would use async calls to the api (this case numberofblocks = 26 calls in parallel), but I do not know how would I do that. formatter.ReadFrom returns void, thus I can not use it with Task.
How can I solve this, and how can I read multiple xml feeds at the same time?
Normally I would use async calls to the api (this case numberofblocks = 26 calls in parallel), but I do not know how would I do that. formatter.ReadFrom returns void, thus I can not use it with Task.
Atom10FeedFormatter is a very dated type at this point, and it doesn't support asynchrony. Nor is it likely to be updated to support asynchrony.
How can I solve this, and how can I read multiple xml feeds at the same time?
Since you're stuck in the synchronous world, you do have the option of using "fake asynchrony". This just means you would do the synchronous blocking work on a thread pool thread, and treat each of those operations as though they were asynchronous. I.e.:
var tasks = new List<Task<Atom10FeedFormatter>>();
for(int i = 0; i++; i<numberofblocks) {
int skip = i*20;
int top = 20;
tasks.Add(Task.Run(() =>
{
string odataurl = "http://{mysite}/_api/ProjectData/Projects"+"?&$skip="+skip+"&top=20";
Atom10FeedFormatter formatter = new Atom10FeedFormatter();
using (XmlReader reader = XmlReader.Create(odataurl))
{
formatter.ReadFrom(reader);
return formatter;
}
}));
}
var formatters = await Task.WhenAll(tasks);
I am trying the async examples from the GNOME project site. I get the follwoing warning which I don't under stand on how to fix.
async.vala:8.2-8.17: warning: delegates with scope="async" must be owned
Code
async double do_calc_in_bg(double val) throws ThreadError {
SourceFunc callback = do_calc_in_bg.callback;
double[] output = new double[1];
// Hold reference to closure to keep it from being freed whilst
// thread is active.
// WARNING HERE
ThreadFunc<bool> run = () => {
// Perform a dummy slow calculation.
// (Insert real-life time-consuming algorithm here.)
double result = 0;
for (int a = 0; a<100000000; a++)
result += val * a;
output[0] = result;
Idle.add((owned) callback);
return true;
};
new Thread<bool>("thread-example", run);
yield;
return output[0];
}
void main(string[] args) {
var loop = new MainLoop();
do_calc_in_bg.begin(0.001, (obj, res) => {
try {
double result = do_calc_in_bg.end(res);
stderr.printf(#"Result: $result\n");
} catch (ThreadError e) {
string msg = e.message;
stderr.printf(#"Thread error: $msg\n");
}
loop.quit();
});
loop.run();
}
The warning is pointing at the run variable inside the async function. Who or what needs to be owned? The reference to the closure?
The delegate needs to have a well defined owner all the time. The error message is a bit misleading.
To fix it you have to explicitly transfer the ownership from the delegate to the thread constructor:
new Thread<bool>("thread-example", (owned) run);
Instead of
new Thread<bool>("thread-example", run);
See also: https://wiki.gnome.org/Projects/Vala/Tutorial#Ownership
PS: The generated C code is fine in both cases. (at least with valac 0.46.6)
First time writing an AsyncTask and I seem to have a subtle design flaw that prevents both ProgressDialog, ProgressBar, and even Log.d() from working properly. I suspect that somehow I am not actually creating a new thread/task.
Short: the symptoms
A ProgressDialog is created in the constructor, and the code orders Android to show it in onPreExecute(), but the dialog never shows.
onProgressUpdate() is supposed to execute whenever I call publishProgress() from within doInBackground(), correct? Well, it doesn't. Instead, it executes when doInBackground() completes.
Long: investigations
Things I have verified through the emulator and, when possible, on a phone:
onPreExecute() is definitely called
the progress bar is not reset until after doInBackground() completes
update_dialog.show() is definitely executed, but the dialog does not appear unless I remove the .dismiss() in onPostExecute(); I imagine dialog is, like the progress bar, not shown until after doInBackground() completes, but is naturally immediately dismissed
the code will happily show dialogs when no computation is involved
doInBackground() definitely invokes publishProgress()
when it does, onProgressUpdate() does not execute immediately! that is, I have a breakpoint in the function, and the debugger does not stop there until after doInBackground() completes! (perhaps this is a phenomenon of the debugger, rather than doInBackground(), but I observe the same symptoms on a mobile device)
the progress bar gets updated... only after doInBackground() completes everything
similarly, the Log.d() data shows up in Android Monitor only after doInBackground() completes everything
and of course the dialog does not show up either in the emulator or on a device (unless I remove .dismiss() from onPostExecute())
Can anyone help find the problem? Ideally I'd like a working dialog, but as Android has deprecated that anyway I'd be fine with a working progress bar.
Code
Here are the essentials, less the details of computation &c.:
Where I call the AsyncTask from the main thread:
if (searching) { // this block does get executed!
Compute_Task my_task = new Compute_Task(overall_context, count);
my_task.execute(field, count, max_x, max_y);
try { result = my_task.get(); } catch (Exception e) { }
}
The AsyncTask itself:
private class Compute_Task extends AsyncTask<Object, Integer, Integer> {
public Compute_Task(Context context, int count) {
super();
current_positions = 0;
update_dialog = new ProgressDialog(context);
update_dialog.setIndeterminate(true);
update_dialog.setCancelable(false);
update_dialog.setTitle("Thinking");
update_dialog.setMessage("Please wait");
}
protected void onPreExecute() {
super.onPreExecute();
update_dialog.show();
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.setProgress(0);
}
protected void onPostExecute() {
super.onPostExecute();
update_dialog.dismiss();
}
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.incrementProgressBy(1);
Log.d(tag, values[0].toString());
}
protected Integer doInBackground(Object... params) {
Integer result = compute_scores(
(boolean[][]) params[0], (Integer) params[1], (Integer) params[2], (Integer) params[3], 0)
);
return result;
}
public int compute_scores(boolean[][] field, int count, int max_x, int max_y, int level) {
int result, completed = 0;
switch(count) {
// LOTS of computation goes on here,
// including a recursive call where all params are modified
if (level == 0)
publishProgress(++completed);
}
}
ProgressDialog update_dialog;
}
Turns out this is basically the same issue as the one given here. The "fatal" line is this one:
try { result = my_task.get(); } catch (Exception e) { }
Apparently this puts the UI thread into deep sleep. One should not use get() with an AsyncTask unless one is willing to suspend the UI thread. We have to perform a little magic in onPostExecute() instead.
Although it turns out that this was a duplicate, I didn't find it until after I wrote it, because I didn't realize the thread was blocking.
I'm new to RX, and I have my desired scenario working well, but it seems to me there must be a simpler or more elegant way to achieve this. What I have is an IObservable<T> and I want to subscribe to it in such a way that I end up with an IObservable<U>, by triggering an asynchronous operation that generates a U for each T it sees.
What I have so far (that works great, but seems cumbersome) uses an intermediate event stream and goes something like this:
public class Converter {
public event EventHandler<UArgs> UDone;
public IConnectableObservable<U> ToUs(IObservable<T> ts) {
var us = Observable.FromEvent<UArgs>(this, "UDone").Select(e => e.EventArgs.U).Replay();
ts.Subscribe(t => Observable.Start(() => OnUDone(new U(t))));
return us;
}
private void OnUDone(U u) {
var uDone = UDone;
if (uDone != null) {
uDone(this, u);
}
}
}
...
var c = new Converter();
IConnectableObservable<T> ts = ...;
var us = c.ToUs(ts);
us.Connect();
...
I'm sure I'm missing a much simpler way to do this...
SelectMany should do what you need, to flatten out the IO<IO<T>>
Observable.Range(1, 10)
.Select(ii => Observable.Start(() =>
string.Format("{0} {1}", ii, Thread.CurrentThread.ManagedThreadId)))
.SelectMany(id=>id)
.Subscribe(Console.WriteLine);
This is exactly what SelectMany is for:
IObservable<int> ts
IObservable<string> us = ts.SelectMany(t => StartAsync(t));
us.Subscribe(u =>
Console.WriteLine("StartAsync completed with {0}", u));
...
private IObservable<string> StartAsync(int t)
{
return Observable.Return(t.ToString())
.Delay(TimeSpan.FromSeconds(1));
}
Keep in mind that if StartAsync has a variable completion time, you may receive the output values in a different order from the input values.