Rx Observable only works once? - vb.net

I have the following code which is being called from a Web Api. As you can see I want to return as soon as I can and shift the work onto the threadpool. (The client polls to see when the job is complete. But the polling is nothing to do with this. The purpose of these routines is simply to extract data and write a file away in background whilst maintaining the progress of the job in a table. The client will interrogates this to determine whether the file is ready so I'm not trying to push progress messages to the client.)
Public Function Extract(filepath as string, ...) as ExtractResult
dim source = ExtractInternal(filepath, ...)
' works first time it is called only!
using source.SubscribeOn(ThreadPoolScheduler.Instance)
.SubScribe()
end using
' works every time it is called ...
dim subscription = source.SubscribeOn(ThreadPoolScheduler.Instance)
.SubScribe()
Return New ExtractResult()
End Function
Public Function ExtractInternal(filepath as string, ...) as IObservable(of Unit)
return Observable.Create(of Unit)
Function()
....
uses filepath here
Return Disposable.Empty
End Function
End Function
As you can see in my comments, if I use auto-disposing of Using ..., I am finding that the observable gets called on the first occasion but not thereafter. Whereas if I assign the subscription to a local var it works every time the web call invokes the routine but I'm concerned that I'm actually leaving stuff hanging around.
Could someone explain why the observable doesn't get re-instantiated on subsequent calls and perhaps explain how I can get it to work every time and tidy up afterwards properly.
EDIT:
So I ended up using Observable.Defer which seems tom give me what I am after ...
Public Function Extract(filepath as string, ...) As ExtractResult
Observable.Defer(Function() ExtractInternal(filepath, ...) _
.SubscribeOn(NewThreadScheduler.Default) _
.Subscribe()
Return New ExtractResult()
End Function
I'm wondering if this is perhaps the correct way to do it to give me proper disposal whilst also using the current parameter values.
Could anyone confirm or correct?
EDIT 2
That was wrong! In fact if I rewrite it as
Public Function Extract(filepath as string, ...) As ExtractResult
Using Observable.Defer(Function() ExtractInternal(filepath, ...)
.SubscribeOn(NewThreadScheduler.Default) _
.Subscribe()
End Using
Return New ExtractResult()
End Function
I get the same behaviour as I originally was getting when I wrote the post.
One thing (amongst many) I don't understand is why if the observable is local var, when a second call is made to the Extract method, another observable is not created and subscribed to? It seems to go against scoping logic if I am actually referencing the same observable under the hood? I've obviously misunderstood.
Many thx
S

Yes, when you dispose the subscription, it stops receiving notifications.
You should keep it in an instance field and have the class implement disposable. Consumers of this class can then dispose it at their convenience.
In your Dispose implementation, you call subscription.Dispose().

Related

In VB.Net, how can I create a method that waits for a variable number of asynchronous calls to complete, and then returns a result?

How can I code a method in VB.Net 2012 that waits for a variable number of asynchronous calls to complete, and only when all calls finish will then return a result?
I'm writing an app that retrieves a value from various web pages, and then returns the sum of those values. The number of values to retrieve will be determined by the user at runtime. As web retrieval is asynchronous by nature, I'm trying to make the app more efficient by coding it as such. I've just read about the keywords Async and Await, which seem perfect for the job. I also found this example of how to do it in C#: Run two async tasks in parallel and collect results in .NET 4.5.
But there are two issues with this example: 1) At first glance, I don't know how to make the same thing happen in VB.Net, and 2) I don't know how it could be redesigned to handle a variable number of called tasks.
Here's a pseudo-translation from the example, of what I hope to achieve:
Function GetSumOfValues(n as Integer)
For i = 1 To n
GetValueAsync<i>.Start()
Next i
Dim result = Await Task.WhenAll(GetValueAsync<?*>)
Return result.Sum()
End Function
Note the question mark, as I'm not sure if it's possible to give WhenAll a "wildcarded" group of tasks. Perhaps with an object collection?
You can use this example of using tasks with Task.WaitAll
Now, to collect data asynchronously, you can use a static method with sync lock. Or one of the synchronized collections

VB NET How to execute some code at the start and at the end of any function

I like to try to optimize my code, and I would like to measure the time taken by a function.
I have a class named Chrono. So I just have to add chrono.start at the beginning of the function, and chrono.stop at the end. My class chan also add the times it measure in a list, to then have average time, total time...
It works. Only problem is when there is exit sub or return in the middle of the function. Not really a problem, I just add a Try at the begginf of the function, and put my chrono.stop in the finally portion. I'm not sure it's really efficient, but it works.
So here is my question : I would like to have a function taking function name as parameter, that will automatically launch and stop my class when this function is called. I have heard of Reflection, but I have no idea how to use it. And it's really hard to search for this question in the internet (because the words are too common : "do something at the end of a function")
To resume, my code works, no problem. It's just constraining to add code to a function for just a short period of time (and sometimes forgot to remove it).
Thx (I'm french and hope I'm understandable)
This is how you can use reflection to call a method by name:
using System.Reflection;
public int InvokeMethod(string name)
{
int time1 = 1; //call your chrono.start here.
Type thisType = this.GetType();
MethodInfo theMethod = thisType.GetMethod(name);
theMethod.Invoke(this, new object[] { 1 });
int time2 = 10; //call your chrono.end here.
return time2 - time1;
}
However, there is a problem. How will you know what parameters to pass to the function? In the code above, I'm passing the integer 1 (new object[] { 1 }) just for example. So this code cannot be automated, but if you run it manually against each function one by one, then you can change that line to pass the correct arguments and make it work without having to modify your function.
This is to answer your question as how to call a function by name using reflection. However, it is much easier to call it using a delegate (or Fuc<T, tRsult> in .Net v3.5 and higher).

MATLAB - objects not clearing when timers are involved

This is somewhat related to this question, but not quite.
I have two classes, FunctionWrapper and TimerWrapper:
classdef FunctionWrapper < handle
methods
function Fcn(obj)
disp('FunctionWrapper.Fcn was called!');
end
end
end
classdef TimerWrapper < handle
properties
Timer
end
methods
function obj = TimerWrapper(other_object)
obj.Timer = timer;
set(obj.Timer, 'Period', 1);
set(obj.Timer, 'ExecutionMode', 'fixedSpacing');
set(obj.Timer, 'TimerFcn', #(event, data) other_object.Fcn);
end
function start(obj)
start(obj.Timer);
end
function stop(obj)
stop(obj.Timer);
end
function delete(obj)
disp('destructor called!');
delete(obj.Timer);
end
end
end
Say I execute the following code in the Command Window:
>> F = FunctionWrapper;
>> T = TimerWrapper(F);
>> clear T %# T's destructor not called
>> timerfind %# just to verify that no, the destructor was never called
Timer Object: timer-1
Timer Settings
ExecutionMode: fixedSpacing
Period: 1
BusyMode: drop
Running: off
Callbacks
TimerFcn: #(event,data)other_object.Fcn
ErrorFcn: ''
StartFcn: ''
StopFcn: ''
What's going on here? I know that timer objects need to be manually deleted, but I thought that would be dealt with in the destructor for TimerWrapper. Without using Amro's ugly but straightforward workaround to overload the clear command, is there a way to clear T from the workspace? Furthermore, nothing is referring to T, so why does a reference to it exist? (The fact that the destructor is never called implies this fact.) Is this buried in the timer object itself?
If you type t = TimerWrapper; f = functions(t.Timer.TimerFcn); f.workspace(2), you'll see that the workspace of the anonymous function used for the callback contains a reference to the TimerWrapper object itself. So there's a kind of circular reference there which is not picked up by clear.
Given how you've set things up, you can remove T (and its underlying timer object) by calling the destructor explicitly and then calling clear.
T.delete
clear T
The difference between clear and delete is kind of confusing (to me, anyway). As you've found, clear doesn't explicitly call the destructor. It just removes the name T from the workspace. So T, and its underlying timer, still exist at that point. If they contained no references to things that still existed, MATLAB would then remove T properly, including calling its destructor. As it is, since the timer contains a reference (in its callback) to T, which still exists, the timer (and thus T as well) is not deleted.
You can find it (despite not having a name in the workspace) with timerfindall, and if you explicitly delete it yourself using
tmrs = timerfindall;
delete(tmrs);
you'll find that T is now properly gone.
I'm not so sure that this is a bug, although I find it pretty confusing, and the distinction between clear and delete could probably be documented better.
As to a workaround, I don't find it a big pain to explicitly call delete, although it's a bit more of a pain to clean things up if you accidentally call clear. I would think the suggestion in message #5 from the thread you linked to, rather than message #4, would be more general and robust.
I don't think you should overload clear in the way #Amro suggests in the separate thread you linked to: although this may work if you call clear T explicitly, you may still get into trouble if you call clear all, or clear variables. (I haven't tried it just now, but I believe these syntaxes of clear don't even loop over things in the workspace and call clear on each - instead they call the clear method of the internal MATLAB workspace object, and that's going to get confusing fast).
It seems as though this might be because the timer's callback is set to a non-default value. A proposed workaround (see message#4 of the linked thread) is to set the callback function only when the start method is called, then setting it to null when the stop method is called.

How to make function wait to return after getResult from SQL Statement is available?

I'm just trying to make a simple function that will return all the data from my SQLITE database as an array. But it looks like when my function is returning the array, the SQL statement is actually still executing... so it's empty... Does anyone have a suggestion? Or am I just going about this whole thing wrong.
I know I could just have the event listener functions outside this function, and they could then set the data. But i'm trying to make a AS3 Class that holds all my SQL functions, and It would be nice to have everything for this particular function just in one function, so it can return an array to me.
public function getFavsGamesArray():Array
{
getFavsArraySql.addEventListener(SQLEvent.RESULT, res);
getFavsArraySql.addEventListener(SQLErrorEvent.ERROR, error);
getFavsArraySql.text = "SELECT * FROM favGames";
getFavsArraySql.execute();
var favsArr:Array = new Array();
function res(e:SQLEvent):void
{
trace("sql good!");
favsArr=getFavsArraySql.getResult().data;
}
function error(e:SQLEvent):void
{
trace("sql error!");
}
trace(favsArr);
return favsArr;
}
Assuming I understood your question, Instead of expecting getFavsGamesArray() to actually return the results from an asynchronous event (which it likely never will), consider passing a function (as an argument) to call within your res() function that would then process the data.
In your SQL helper class, we'll call it SQLHelper.as:
private var processResultsFun:Function;
public function getFavsGamesArray(callBackFun:Function):void
{
processResultsFun = callBackFun;
...
} //Do not return array, instead leave it void
function res(e:SQLEvent):void
{
trace("sql good!");
if(processResultsFun != null)
{
processResultsFun(getFavsArraySql.getResult().data);
}
}
In the class(es) that call your SQL helper class:
function processRows(results:Array):void {
//Make sure this function has an Array argument
//By the time this is called you should have some results
}
...
SQLHelper.getFavsGamesArray(processRows);
You can optionally pass an error handling function as well.
Your problem is that your task is asynchronous.
favsArris a temporary variable, and you return its value directly when getFavsGamesArray completes. At that time, the value will always be null, because the listener methods are called only after the SQL statement is complete - which will be at some time in the future.
You need some way to delay everything you are going to do with the return value, until it actually exists.
The best way to do it is to dispatch your own custom event, and add the value as a field to the event object, or to add a listener method outside of your SQL class directly to the SQLStatement - and have it do stuff with event.target.getResult().data. That way you can always be sure the value exists, when processing occurs, and you keep your SQL behavior decoupled from everything on the outside.
I would also strongly encourage you not to declare your event listeners inside functions like this: You can't clean up these listeners after the SQL statements completes!
True: Declaring a function inside a function makes it temporary. That is, it exists only for the scope of your function, and it is garbage collected when it's no longer needed - just like temporary variables. But "it is no longer needed" does not apply if you use it as an event listener! The only reason this works at all is that you don't use weak references - if you did, the functions would be garbage collected before they are even called. Since you don't, the listeners will execute. But then you can't remove them without a reference! They continue to exist, as will the SQL statement, even if you set its references to null - and you've successfully created a memory leak. Not a bad one, probably, but still...
If you really want to encapsulate your SQL behavior, that is a good thing. Just consider moving each SQL statement to a dedicated class, instead of creating one giant SQLHelper, and having your listener methods declared as member functions - it is much easier to prevent memory leaks and side effects, if you keep references to everything, and you can use these in a destroy method to clean up properly.

Is this a UI-threading issue? Is there an easy way to fix it?

I am communicating with a USB-HID device. It will successfully complete hundreds of send-receive requests but occasionally get a Null Exception error.
Is this a threading issue?
FormMain.vb:
myHidDevice.transmitPacket(Packet)
myHidDevice.resetEvent.WaitOne(6)
If myHidDevice.rxDataReady = True then
' Life is good
MyHidDevicePort.vb
Public Sub DataReceivedHandler(ByVal sender as Object, dataReceived as DataReceivedEventArgs)
if dataReceived.data Is Nothing Then
Exit Sub
Else
Dim rDataPacket As List(Of Byte) = dataReceived.data.ToList()
For Each element in rDataPacket
rxData.dataPacket(i) = element
rxDataReady = True
resetEvent.Set()
MySensorClass.vb
Public Overrides Function processPacket(ByRef rxStruct as rStruct, ByVal txPacket()) as Boolean
....
Select Case rxStruct.dataPacket(4)
Case MOD_DISPLAY_SET_BRIGHTNESS
rxData(0) = rxStruct.dataPacket(5)
...
at the rxData.dataPacket(i) = element I will get a NullReference error every now and then. I could enclose it in a try/catch statement, but I'd like to fix the root problem if possible.
This device is communicating to microcontrollers, and it is possible that they won't always give a value... but my feeling is this is some sort of UI threading issue. When debugging, even though there is a null exception, many times there actually does seem to be data in dataReceived.data.ToList(). Is there an easy way to place the whole data processing routine on a thread separate from the UI?
Edit: Changed code to match answer and give more info on where it is used. Still get NullReferenceExceptions after about 1,000 completed send/receive requests to the HID device.
The dialog in the comments is too restricting, so I'll try this as an answer. Unfortunately, there still isn't enough code to give a full answer.
Some sample unknowns:
What is rxData (a custome class, part of the SDK, a struct)?
Where does i come from in the code sample rxData.dataPacket(i) = element, I don't see it decalred or incremented.
Why is the form waiting on myHidDevice.resetEvent.WaitOne(6) and what does it do once it thinks there is sucess?
How/when does processPacket get called?
What I can recommend in general is that access to shared state be wrapped in a SyncLock. And in your case, that includes both rxData and rxDataReady.
In your threaded event callback you need this:
SyncLock(syncRoot)
For Each element in rDataPacket
rxData.dataPacket(i) = element
next
rxDataReady = True
resetEvent.Set()
End SyncLock
And in your Main form where you are waiting for a response you need to wrap access to the ready flag as well:
SyncLock(myHidDevice.syncRoot)
If myHidDevice.rxDataReady = True then
' do something that consumes the data read in the thread
End If
End SyncLock
You have to watch for how long you hold the lock in the read and the write because you cannot be doing both at the same time.
Over all, I wouldn't be surprised if your code code be refactored a bit to make the thread issues easier to deal with. A blocking queue / colletion as you suggested might be a good idea. Just not enough is known of you design/code to give any more concrete advice.
If you know that there is a possibility that your object may be null, placing it inside of a try-catch block would be the incorrect way of handling this situation, as that would be considered coding by exception. Instead, do a null check on your object prior to setting it. e.g.
If Not dataReceived.data Is Nothing Then
Dim rDataPacket As List(Of Byte) = dataReceived.data.ToList()
End If
If your problem lyes with the individual array elements being null, you should also check them to ensure they exist before setting/accessing them.