This question already has answers here:
Dart language support async/await programming style, or similar? [duplicate]
(2 answers)
Closed 9 years ago.
Does Dart have anything remotely similar to the async/await pattern in .net?
For example, I want to open a socket and do several handshakes: send 1, wait for response 1, send 2, wait for response 2 etc. Waiting for a response shouldn't be blocking obviously, that's what async is all about.
Here's one way of doing it:
Socket _socket;
Socket.connect(_host, _port).then(
(Socket socket) {
print("socket open!");
_socket = socket;
socket.transform(new StringDecoder()).listen(ProcessResponse);
socket.write("1");
});
void ProcessResponse(String response)
{
print("response received!");
if (response == "1") _socket.write("2");
if (response == "2") _socket.write("3");
if (response == "3") _socket.write("4");
// ... etc ..
}
I'd love to be able to write something like
socket.write("1");
response1 = await socket.getResponse();
socket.write("2");
response2 = await socket.getResponse();
socket.write("3");
response3 = await socket.getResponse();
// etc.
i.e. write code that looks sync and is much easier to understand, but actually runs async.
Any ideas?
No, not yet. This is a pretty widely desired feature, though. See https://code.google.com/p/dart/issues/detail?id=104 (and star the issue).
Now it has:
https://www.dartlang.org/articles/await-async/
Related
I am currently implementing a simple ONVIF client program in dart and am having a bit of trouble with handling futures in the http.dart package.
In my code below, the client.post() method returns a Future<response> (containing body/header/status code and so on...) and in my case I would need to receive this before the if/else statement, hence why I have used await. Trouble is the program just hangs and doesn't proceed past the client.post()line.
I know I might need to do a client.close() somewhere but I've tried lots of different ways and nothing works. Here is my current code with some comments to try and explain it a bit:
// The Variables:
// reqSysDateAndTime is a soap message we are sending to the device.
// onvifDev is just a place where the device details are stored.
// probeMatch is a class that stores important info from the ws-discovery stage.
Future<String> checkXaddrsAndGetTime(Device onvifDev, ProbeMatch probeMatch) async {
// Set up the client and uri.
Uri uri = Uri.parse(probeMatch.xaddrs);
http.Client client = http.Client();
// Send the POST request, with full SOAP envelope as the request body
print('[Setup]: Listening for Date/Time response...');
Response response = await client.post(uri, body: reqSysDateAndTime);
print("${response.body}");
// Determine if the address is usable or not.
if (response != null) {
// Set this address as 'working'
onvifDev.xAddrs = probeMatch.xaddrs;
return response.body;
}
else {
return null; // The address does not work
}
}
I also know that this isn't an issue with the actual body of the request because if I do...
client.post(uri, body: reqSysDateAndTime).then((onValue) => print(onValue.body));
...instead, it will print out the response which I'm expecting.
I understand that this is probably a small fix that I'm missing but any help would be much appreciated.
Cheers.
To briefly answer my own question, turns out it was a silly error on my part where the address I was using was link-local - hence why it was hanging at client.post(). There is a nice method in the InternetAddress class here, amongst some other useful methods, which checks to see if the address is link-local or not.
Looks like my Firestore requests are being throttled! (see picture below)
If I had to guess, I'd say it's not Firestore doing the throttling, it's actually Chrome... I've seen this kind of throttling before.
One way to get around Chrome's throttling here is to combine multiple requests into one.
As I sit here thinking "I wonder if Firestore can combine these read requests?", I notice that, coincidentally, the requests to Firestore are actually named batchGet! But oddly enough, each batchGet request only has one read inside it:
So, in an effort to avoid Chrome's throttling, my question is: how do I request multiple documents at the same time in Firestore? I suspect it's possible because, well, there's a server endpoint named batchGet. Is it possible?
Many thanks!
Just dug through the source a bit, looks like it's impossible. Transaction's .get() method looks like this:
Transaction.prototype.get = function (documentRef) {
var _this = this;
validateExactNumberOfArgs('Transaction.get', arguments, 1);
var ref = validateReference('Transaction.get', documentRef, this._firestore);
return this._transaction
.lookup([ref._key])
.then(function (docs) {
if (!docs || docs.length !== 1) {
return fail('Mismatch in docs returned from document lookup.');
}
var doc = docs[0];
if (doc instanceof NoDocument) {
return new DocumentSnapshot(_this._firestore, ref._key, null, false);
}
return new DocumentSnapshot(_this._firestore, ref._key, doc, false);
});
};
That .lookup() takes an array of all the documents to put into the batchGet request, and it's coded here to only ever have one element in that array.
So, looks like there's no way to get multiple documents in one batchGet request.
Sorry for the beginers question, I read a lot of post here and on the web and there is something fondemental I can't understand.
As I understood, the usage of async actions in WebAPI is mainly for scalability reasons, so any incoming request will be diverted to a worker instead to a thread and by that, more requests could be served.
My project consists on several huge actions that read/insert/update from DB by EF6 many times. the action looks like that:
public async Task<HttpResponseMessage> Get(int id)
{
PolicyModel response = await policyRepository.GetPolicyAsync(id);
return Request.CreateResponse<PolicyModel>(HttpStatusCode.OK,response);
}
and GetPolicyAsync(int id) looks like that:
public async Task<PolicyModel> GetPolicyAsync(int id)
{
PolicyModel response = new PolicyModel();
User currentUser = await Repositories.User.GetUserDetailsAsync(id);
if(currentUser.IsNew)
{
IEnumerable<Delivery> deliveries = await Repositories.Delivery.GetAvailableDeliveries();
if(deliveries == null || deliveries.Count() == 0
{
throw new Exception("no deliveries available");
}
response.Deliveries = deliveries;
Ienumerable<Line> lines = await Repositores.Delivery.GetActiveLinesAsync();
lines.AsParallel().ForAll(line => {
await Repositories.Delivery.AssignLineAsync(line,currentUser);
}
...
return response;
}
I didn't write the entire code but it goes quite a bit and it is also broken into several methods but that is the spirit of it
now the question i have is: is it a good practice to use so many awaiters in one method? I saw that it is more difficult to debug, is it hard to maintain the thread context and for the sake of worker assignment, shouldn't I just use Task.Factory.StartNew() or maybe call a simple Task.Delay() so that the request will immidiatelly be diverted to a worker?
I know that it is not a good practice (async all the way) so maybe just one async method at the end/begining of the GetpolicyAsync(int id) method
EDIT:
as I understood the mechanics of the async methods in .net, for every async method, the compiler is looking for a free thread and let it deal withthe method, the thread is looking for a free worker and assign the method to it and then report back to the compiler that it is free. so if we have 10 threads and for every thread there are 10 workers, the program can deals with 100 concurrent async methods.
so back to web developement, the IIS assign x thread to each app pool, 10 for instance. that means that the async WebAPI method can handle 100 requests but if there is another async method inside, the amount of requests that can be dealth with are 50 and so on, am I right?
and as I understood, I must call an async method in order to make the WebAPI method truely async and now, since it is a bad practice to use Task.Factory.StartNew(), I must at least use Task.Delay()
what I really want to gain is the scalability of the async WebAPI methods and the context awareness of synced methods
in all the examples I've seen so far, they only show a very simple code but in real life, methods are far more complex
Thanks
There's nothing wrong with having many awaits in a single method. If the method becomes too complicated for you you can split it up into several methods:
public async Task<PolicyModel> GetPolicyAsync(int id)
{
PolicyModel response = new PolicyModel();
User currentUser = await Repositories.User.GetUserDetailsAsync(id);
if(currentUser.IsNew)
{
await HandleDeliveriesAsync(await Repositories.Delivery.GetAvailableDeliveries());
}
...
return response;
}
public async Task HandleDeliveriesAsync(IEnumerable<Delivery> deliveries)
{
if(deliveries == null || deliveries.Count() == 0
{
throw new Exception("no deliveries available");
}
response.Deliveries = deliveries;
Ienumerable<Line> lines = await Repositores.Delivery.GetActiveLinesAsync();
lines.AsParallel().ForAll(line => {
await Repositories.Delivery.AssignLineAsync(line,currentUser);
}
Don't use Task.Factory.StartNew or Task.Delay as it just offloads the same work to a different thread. It doesn't add any value in most cases and actually harms in ASP.Net.
After much search, I came across this artical:
https://msdn.microsoft.com/en-us/magazine/dn802603.aspx
it explains what #i3arnon said in the comment. there are no workers at all, the threads are doing all the work.
In a nutshell, the thread that handles a web request reach to an opporation that is designed to be done asyncronically on the driver stack, it creates a request and pass it to the driver. The driver mark it as pending and reports "done" to the thread which goes back to the thread pool to get another assignment. The actual job is not being done by threads but by the driver that borrowing cpu time from all threads and leave them free to attend to their businesses. When the opporation is done, the driver notifies it and an available thread comes to continue...
so, from that I learn that I should look into each and every async method and check that it actually does an opporation that uses the drivers asyncronically.
Point to think: the scallability of your website is dependent on the amount of opporations that are truly being done asyncronically, if you don't have any of them, then your website won't scale.
moderators, I'm a real newbe, if I got it all wrong, please correct me
Thanks!
at this moment I am developing an android db access to a servicestack web api.
I need to show a message of "wait please..." when the user interacts with the db, I read some documentation:
Calling from client side an async method
But I cannot found how the async method must be implemented in the webapi, serverside.
Can you please share a link to the documentation? or a simple working sample?
I have this before trying to convert it to an async call.
var response = jsonClient.Send(new UsuarioLogin { Cuenta = txtCuenta.Text, P = txtPass.Text});
After some read, the latter code is converted into this:
var response = await jsonClient.SendAsync(new UsuarioLogin { Cuenta = txtCuenta.Text, P = txtPass.Text});
So, in the server side I have this(just an extract):
public object Post(UsuarioLogin request)
{
var _usuario = usuarioRepo.Login(_cuenta, _password);
if (_usuario != null)
{
if (_usuario.UsuarioPerfilId != 2 )
{
return new UsuarioLoginResponse { Ret = -3 };
}
How can I convert it to an async method?
Thanks in advance.
Server-side and client-side async are opaque and unrelated, i.e. an async call on the client works the same way irrespective if it's calling a sync or an async service, there's also no difference for sync client either. Essentially how the server is implemented has no effect on how it's called on the client.
To make an async service on the Server you just need to return a Task, you can look at the AsyncTaskTests for different examples of how to create an async Service.
There are a lot of benefits for making non-blocking async calls on the client since this can be called from the UI thread without blocking the UI. But there's less value of server-side async which adds a lot of hidden artificial complexity, is easy to deadlock, requires rewriting I/O operations to be async and in many cases wont improve performance unless I/O is the bottleneck, e.g. async doesn't help when calling a single RDBMS. You're going to get a lot more performance benefits from using Caching instead.
I understand how to make a message based non-blocking application in akka, and can easily mock up examples that perform
concurrent operations and pass back the aggregated results in a message. Where I have difficulty is understanding what my
non-blocking options are when my application has to respond to an HTTP request. The goal is to receive a request and
immediately hand it over to a local or remote actor to do the work, which in turn will hand it off to get a result that
could take some time. Unfortunatly under this model, I don't understand how I could express this with a non-blocking
series of "tells" rather than blocking "asks". If at any point in the chain I use a tell, I no longer have a future to
use as the eventual response content (required by the http framework interface which in this case is finagle - but that is not
important). I understand the request is on its own thread, and my example is quite contrived, but just trying to
understand my design options.
In summary, If my contrived example below can be reworked to block less I very much love to understand how. This is my
first use of akka since some light exploration a year+ ago, and in every article, document, and talk I have viewed says
not to block for services.
Conceptual answers may be helpful but may also be the same as what I have already read. Working/Editing my example
would likely be key to my understanding of the exact problem I am attempting to solve. If the current example is generally
what needs to be done that confirmation is helpful too, so I don't search for magic that does not exist.
Note The following aliases: import com.twitter.util.{Future => TwitterFuture, Await => TwitterAwait}
object Server {
val system = ActorSystem("Example-System")
implicit val timeout = Timeout(1 seconds)
implicit def scalaFuture2twitterFuture[T](scFuture: Future[T]): TwitterFuture[T] = {
val promise = TwitterPromise[T]
scFuture onComplete {
case Success(result) ⇒ promise.setValue(result)
case Failure(failure) ⇒ promise.setException(failure)
}
promise
}
val service = new Service[HttpRequest, HttpResponse] {
def apply(req: HttpRequest): TwitterFuture[HttpResponse] = req.getUri match {
case "/a/b/c" =>
val w1 = system.actorOf(Props(new Worker1))
val r = w1 ? "take work"
val response: Future[HttpResponse] = r.mapTo[String].map { c =>
val resp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
resp.setContent(ChannelBuffers.copiedBuffer(c, CharsetUtil.UTF_8))
resp
}
response
}
}
//val server = Http.serve(":8080", service); TwitterAwait.ready(server)
class Worker1 extends Actor with ActorLogging {
def receive = {
case "take work" =>
val w2 = context.actorOf(Props(new Worker2))
pipe (w2 ? "do work") to sender
}
}
class Worker2 extends Actor with ActorLogging {
def receive = {
case "do work" =>
//Long operation...
sender ! "The Work"
}
}
def main(args: Array[String]) {
val r = service.apply(
com.twitter.finagle.http.Request("/a/b/c")
)
println(TwitterAwait.result(r).getContent.toString(CharsetUtil.UTF_8)) // prints The Work
}
}
Thanks in advance for any guidance offered!
You can avoid sending a future as a message by using the pipe pattern—i.e., in Worker1 you'd write:
pipe(w2 ? "do work") to sender
Instead of:
sender ! (w2 ? "do work")
Now r will be a Future[String] instead of a Future[Future[String]].
Update: the pipe solution above is a general way to avoid having your actor respond with a future. As Viktor points out in a comment below, in this case you can take your Worker1 out of the loop entirely by telling Worker2 to respond directly to the actor that it (Worker1) got the message from:
w2.tell("do work", sender)
This won't be an option if Worker1 is responsible for operating on the response from Worker2 in some way (by using map on w2 ? "do work", combining multiple futures with flatMap or a for-comprehension, etc.), but if that's not necessary, this version is cleaner and more efficient.
That kills one Await.result. You can get rid of the other by writing something like the following:
val response: Future[HttpResponse] = r.mapTo[String].map { c =>
val resp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
resp.setContent(ChannelBuffers.copiedBuffer(c, CharsetUtil.UTF_8))
resp
}
Now you just need to turn this Future into a TwitterFuture. I can't tell you off the top of my head exactly how to do this, but it should be fairly trivial, and definitely doesn't require blocking.
You definitely don't have to block at all here. First, update your import for the twitter stuff to:
import com.twitter.util.{Future => TwitterFuture, Await => TwitterAwait, Promise => TwitterPromise}
You will need the twitter Promise as that's the impl of Future you will return from the apply method. Then, follow what Travis Brown said in his answer so your actor is responding in such a way that you do not have nested futures. Once you do that, you should be able to change your apply method to something like this:
def apply(req: HttpRequest): TwitterFuture[HttpResponse] = req.getUri match {
case "/a/b/c" =>
val w1 = system.actorOf(Props(new Worker1))
val r = (w1 ? "take work").mapTo[String]
val prom = new TwitterPromise[HttpResponse]
r.map(toResponse) onComplete{
case Success(resp) => prom.setValue(resp)
case Failure(ex) => prom.setException(ex)
}
prom
}
def toResponse(c:String):HttpResponse = {
val resp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
resp.setContent(ChannelBuffers.copiedBuffer(c, CharsetUtil.UTF_8))
resp
}
This probably needs a little more work. I didn't set it up in my IDE, so I can't guarantee you it compiles, but I believe the idea to be sound. What you return from the apply method is a TwitterFuture that is not yet completed. It will be completed when the future from the actor ask (?) is done and that's happing via a non-blocking onComplete callback.