Looking how to build something similar in Swift 3.
I'm used to using this sort of architecture in Unity3d, perhaps there isn't anything similar to handle async data. I've heard of completion blocks + using protocols/delegates to pass data in Swift but I thought it'd be easier to have a public function that gets the data and then use a coroutine to wait until all the data is in the VC to start things up.
Here is C# code I'd use to create them:
List<Int> data = new List<Int>;
private IENumerator get_data()
{
run_async_func_to_get_data();
while(data.count == 0)
{
yield return null;
}
yield break;
}
private IENumerator start_game()
{
yield return get_data();
yield return use_data();
}
void Start()
{
StartCoroutine(start_game);
}
No, Swift do not currently support Unity/C# style coroutines (i.e., yield return style constructs). Such feature is pretty cool by the way ;-)
Having said that, you might want to take a look in the Async framework for a somewhat valid alternative (if you are really looking for async/await abstractions):
Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch
As for Swift native support, we might need to wait for Swift ≥ 5 for something like that to come along:
Actors, async/await, atomicity, memory model, and related topics. This area is highly desired by everyone, as it will open the door for all sorts of new things on the client, server and more. We plan to start formal discussions about this in Phase 2, but it is unfortunately crystal clear that a new concurrency model won’t be done in time for the Swift 4 release. This is simply because it will take more than a 12 months to design and build, and we want to make sure to take time to do it right. It also makes sense for the memory ownership model to be better understood before taking this on.
Related
I have a background task that has several slow steps to be processed in sequence. I am trying to understand any difference between the following two approaches in Swift.
First approach:
import SwiftUI
struct ContentView: View {
var body: some View {
Button("Start Slow Task") {
Task.detached(priority: .background) {
await slowBackgroundTask()
}
}
}
}
func slowBackgroundTask() async {
slowStep1()
slowStep2()
slowStep3()
}
func slowStep1() {
// takes a long time
}
func slowStep2() {
// takes a long time
}
func slowStep3() {
// takes a long time
}
Approach 2 is the same ContentView, but with the functions changed as follows.
func slowBackgroundTask() async {
await slowStep1()
await slowStep2()
await slowStep3()
}
func slowStep1() async {
// takes a long time
}
func slowStep2() async {
// takes a long time
}
func slowStep3() async {
// takes a long time
}
Is there any difference between these two patterns? I would be most grateful to understand this better.
Both versions build and run. I am trying to understand the difference.
Regarding the difference between these two patterns, they both will run the three slow steps sequentially. There are some very modest differences between the two, but likely nothing observable. I’d lean towards the first snippet, as there are fewer switches between tasks, but it almost certainly doesn’t matter too much.
FWIW, one would generally only mark a function as async if it is actually is asynchronous, i.e., if it has an await suspension point somewhere inside it. As The Swift Programming Language says,
An asynchronous function or asynchronous method is a special kind of function or method that can be suspended while it’s partway through execution.
But merely adding async qualifiers to synchronous functions has no material impact on their underlying synchronous behavior.
Now, if you are looking for a real performance improvement, the question is whether you might benefit from parallel execution (which neither of the snippets in the question can achieve). It depends upon a number of considerations:
Are the subtasks actually independent of each other? Or is subtask 1 dependent upon the results of subtask 2? Etc.
Are these subtasks trying to interact some some shared resource? Or is there going to be resource contention as you synchronize interaction with that shared resource?
Is there actually enough work being done in each subtask to justify the (admittedly very modest) overhead of parallel execution? If the subtasks are not sufficiently computationally intensive, introducing parallelism can actually make it slower.
But, if answering the above questions, you conclude that you do want to attempt parallelism, that begs the question as to how you might do that. You could use async let. Or you could use a “task group”. Or you could just make three independent detached tasks. There are a number of ways of tackling it. We would probably want to know more about these three subtasks to advise you further.
As a final, preemptive, observation as you consider parallel execution, please note that the iOS simulators suffer from artificially constrained “cooperative thread pools”. E.g., see Maximum number of threads with async-await task groups. In short, when testing parallel execution in Swift concurrency, it is best to test on a physical device, not a simulator.
I'm working on a greenfield reactive project where a lot of file handling IO is going on. Is it sufficient if I write the IO code in an imperative blocking manner and then wrap them in a Mono, publish them on boundedElastic scheduler? Will the boundedElastic pool size limit the number of concurrent operations?
If this is not the correct method, can you show an example how to write bytes to a file using Reactor?
Is it sufficient if I write the IO code in an imperative blocking manner and then wrap them in a Mono, publish them on boundedElastic scheduler?
This comes down to opinion on some level - but no, certainly not ideal not for a reactive greenfield project IMHO. boundedElastic() schedulers are great for interfacing with blocking IO when you must, but they're not a good replacement when a true non-blocking solution exists. (Sometimes this is a bit of a moot point with file handling, since it depends if it's possible for the underlying system to do it asynchronously - but usually that's possible these days.)
In your case, I'd look at wrapping AsynchronousFileChannel in a reactive publisher. You'll need to use create() or push() for this and then make explicit calls to the sink, but exactly how you do this depends on your use case. As a "simplest case" for file writing, you could feasibly do something like:
static Mono<Void> writeToFile(AsynchronousFileChannel channel, String content) {
return Mono.create(sink -> {
byte[] bytes = content.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
buffer.flip();
channel.write(buffer, 0, null, new CompletionHandler<>() {
#Override
public void completed(Integer result, Object attachment) {
sink.success();
}
#Override
public void failed(Throwable exc, Object attachment) {
sink.error(exc);
}
});
});
}
A more thorough / comprehensive example of bridging the two APIs can be found here - there's almost certainly others around also.
After some researching the java.nio and Spring library I have found the convenient approach to write strings to file as DataBuffers (which perfectly connect with WebFlux) into AsynchronousFileChannel using Spring classes.
It's not "truly" reactive way to write lines in file, but asyncronous and it is still better than using some standard blocking API.
public Mono<Void> writeRows(Flux<String> rowsFlux) {
DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory();
CharSequenceEncoder encoder = CharSequenceEncoder.textPlainOnly();
Flux<DataBuffer> dataBufferFlux = rowsFlux.map(line ->
encoder.encodeValue(line, bufferFactory, ResolvableType.NONE, null, null)
);
return DataBufferUtils.write(
dataBufferFlux,
Path.of("/your_path_to_save_file/file.txt"),
StandardOpenOption.CREATE_NEW
);
}
Of course, for better performance in this case you can buffer your strings in flux and then append those strings to one string and create a data buffer from it.
Or if you already have Flux of data buffers you can write them to file using DataBufferUtils directly.
In Flutter we use async await and Future, can someone explain that if we don't use another thread (which we can't in dart) and run the job on main UIThread only won't the app become choppy because even if we are waiting for the job to execute it will ultimately execute on UIThread only.
I somewhere read about isolates also. But cannot paint the exact picture. If someone can explain in detail.
I think you missed something when it comes to asynchronous methods in Dart.
Dart is a single-threaded programming language, Java or C# are multi-threaded programming languages, forget async as a new thread, it doesn't happen in Dart.
Dart is a single-threaded programming language. This means is that Dart can only run one instruction at a time, while Java could run multiple instructions concurrently.
As a rule, everything you do in Dart will start in UI-Thread. Whatever method you call in Dart, whether using sync, async, then, they will be running on UI-Thread, since Dart is a single thread.
In single-threaded languages like Javascript and Dart, an async method is NOT executed in parallel but following the regular sequence of events, handled by the Event Loop. There are some problems (I would give some approaches, as we will see below) if you run the following code in a multithreaded language where fetch will take some time to execute:
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
You will receive David's data in user, and after that, you will receive your data.
This will lock your UI, unlike languages like Java which have Threads, where you can perform this task in the background, on another thread, and the UI-Thread will run smoothly.
If you do this at Dart
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
user will be null in personalData, because the fetch event is a Future.
How to solve this in Dart?
String user = await Database.fetch(David);
String personalData = await Database.fetch(user);
For those who like a more functional paradigm (I don't like it) you can use then.
Database.fetch(David).then((user){
Database.fetch(user).then((personal){
String personalData = personal;
});
});
However, imagine that you have billions of data in that database, this heavy task will probably cause the animations on your screen to freeze, and you will see a jank in the user's UI, for that purpose isolates were invented.
Dart Isolates give you a way to perform real multi-threading in Dart. They have their own separate heaps(memory), and run the code in the background, just like the Threads of multi-threaded languages. I could explain how isolates work, but it would make this response very long, and the goal is just to differentiate asynchronous from multi-threaded methods.
A simple way to solve the problem above using isolates would be using compute.
Compute was created to facilitate the creation of isolates, you just pass the function and the data that this function will execute, and that's it!
Important to remember that compute is a Future, so you have to use await or then to get its result.
In our example, we could create a new thread and get its result when we finish by just calling compute like this:
String user = await compute(Database.fetch,David);
String personalData = await compute(Database.fetch,user);
Very simple, isn't it?
In summary:
Everything that waits some time to be completed, in Dart is called a "Future".
To wait for the result of a future to be assigned to a variable, use await or then.
The asynchronous methods (await and then) can be used to obtain a result from a Future, and are executed ON THE MAIN THREAD because Dart is single-thread.
If you want to run any function on a new thread, you can create an isolate. Dart offers an easy-to-use isolate wrapper called compute, where you only need to pass one method that will be processed and the data that will be processed, and it will return its result in the future.
NOTE: if you are going to use compute make sure you are using a static or top-level method (see that in the example I used Database.fetch it was no accident if you need to call Database().fetch or need to create an instance of it, means it is not a static method and will not work with isolates).
English is not my first language and I didn't want to write so much because of that, but I hope I helped differentiate between multi-threaded asynchronous programming from single-threaded asynchronous programming.
I have 6 functions. I would like to execute 3 of these functions in the background (asynchronous?), in Xcode for Swift 2. Can you help me, how can I execute this 3 functions without a "freeze" in the UI? Thank you so much!
Martin R's comment is spot on, you should read Apple's concurrency programming guide. But here's one method you might use:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
dispatch_async(queue) {
doSomethingReallySlowAndTedious()
}
Be careful, though. It's especially easy to introduce bugs in your code by just copy-pasting concurrency code. Make sure you know what each function and parameter does.
(Also, consider the worst cases. Can the slow functions get stuck forever? What if the user wants to quit before the slow functions finish?)
Normally I'm well aware that a consideration like this is premature optimization. Right now I have some event handlers being attached inside a foreach loop. I am wondering if this style might be prone to leaks or inefficient memory use due to closures being created. Is there any validity to this thinking?
closures only apply if your event handlers are anonymous methods (including, but not limited to, lambda expressions). If this is the case, you might have a problem. But it should be okay as long as you remove these event handlers at the proper time.
If you are talking about something like this:
foreach (var item in items)
{
item.SomeEvent += delegate {
// do something
};
}
Then the answer is the performance is not noticeable (in my Monotouch experience anyway) as the compiler simply creates a class with a method the same way the Microsoft C# compiler.
The biggest performance bottlenecks I've encountered in Monotouch have been SQLite related, and parsing DateTimes. Everything else, including complex LINQ statements fly on the 3GS - I'm not sure what magic is performed by the AOT compiler but I would only worry if it creeps up into 0.5 or more seconds to perform the task.