Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Pierre Habouzit via swift-evolution
[Sorry I hit send too fast, let me fix two spots I didn't correct]

> On Sep 2, 2017, at 11:09 PM, Pierre Habouzit  wrote:
> 
> 
> -Pierre
> 
>> On Sep 2, 2017, at 9:59 PM, Chris Lattner > > wrote:
>> 
>> On Sep 2, 2017, at 12:19 PM, Pierre Habouzit > > wrote:
> What do you mean by this?
 
 My understanding is that GCD doesn’t currently scale to 1M concurrent 
 queues / tasks.
>>> 
>>> It completely does provided these 1M queues / tasks are organized on 
>>> several well known independent contexts.
>> 
>> Ok, I stand corrected.  My understanding was that you could run into 
>> situations where you get stack explosions, fragment your VM and run out of 
>> space, but perhaps that is a relic of 32-bit systems.
> 
> a queue on 64bit systems is 128 bytes (nowadays). Provided you have that 
> amount of VM available to you (1M queues is 128M after all) then you're good.
> If a large amount of them fragments the VM beyond this is a malloc/VM bug on 
> 64bit systems that are supposed to have enough address space.
> 
>> 
> queues are serial/exclusive execution contexts, and if you're not 
> modeling actors as being serial queues, then these two concepts are just 
> disjoint. 
 
 AFAICT, the “one queue per actor” model is the only one that makes sense.  
 It doesn’t have to be FIFO, but it needs to be some sort of queue.  If you 
 allow servicing multiple requests within the actor at a time, then you 
 lose the advantages of “no shared mutable state”.
>>> 
>>> I agree, I don't quite care about how the actor is implemented here, what I 
>>> care about is where it runs onto. my wording was poor, what I really meant 
>>> is:
>>> 
>>> queues at the bottom of a queue hierarchy are serial/exclusive execution 
>>> contexts, and if you're not modeling actors as being such fully independent 
>>> serial queues, then these two concepts are just disjoint.
>>> 
>>> In GCD there's a very big difference between the one queue at the root of 
>>> your graph (just above the thread pool) and any other that is within. The 
>>> number that doesn't scale is the number of the former contexts, not the 
>>> latter.
>> 
>> I’m sorry, but I still don’t understand what you’re getting at here.
> 
> What doesn't scale is asking for threads, not having queues.
> 
>> 
>>> The pushback I have here is that today Runloops and dispatch queues on 
>>> iOS/macOS are already systems that have huge impedance mismatches, and do 
>>> not share the resources either (in terms of OS physical threads). I would 
>>> hate for us to bring on ourselves the pain of creating a third completely 
>>> different system that is using another way to use threads. When these 3 
>>> worlds would interoperate this would cause significant amount of context 
>>> switches just to move across the boundaries.
>> 
>> Agreed, to be clear, I have no objection to building actors on top of 
>> (perhaps enhanced) GCD queues.  In fact I *hope* that this can work, since 
>> it leads to a naturally more incremental path forward, which is therefore 
>> much more likely to actually happen.
> 
> Good :)
> 
>>> I'd like to dive and debunk this "GCD doesn't scale" point, that I'd almost 
>>> call a myth (and I'm relatively unhappy to see these words in your proposal 
>>> TBH because they send the wrong message).
>> 
>> I’m happy to revise the proposal, please let me know what you think makes 
>> sense.
> 
> What doesn't scale is the way GCD asks for threads, which is what the global 
> concurrent queues abstract.
> The way it works (or rather limp along) is what we should not reproduce for 
> Swift.
> 
> What you can write in your proposal and is true is "GCD current relationship 
> with the system threads doesn't scale". It's below the queues that the 
> scalability has issues.
> Dave Z. explained it in a mail earlier today in very good words.
> 
>>> My currently not very well formed opinion on this subject is that GCD 
>>> queues are just what you need with these possibilities:
>>> - this Actor queue can be targeted to other queues by the developer when he 
>>> means for these actor to be executed in an existing execution context / 
>>> locking domain,
>>> - we disallow Actors to be directly targeted to GCD global concurrent 
>>> queues ever
>>> - for the other ones we create a new abstraction with stronger and better 
>>> guarantees (typically limiting the number of possible threads servicing 
>>> actors to a low number, not greater than NCPU).
>> 
>> Is there a specific important use case for being able to target an actor to 
>> an existing queue?  Are you looking for advanced patterns where multiple 
>> actors (each providing disjoint mutable state) share an underlying queue? 
>> Would this be for performance reasons, for compatibility with existing code, 
>> or something else?
> 
> Mostly for interaction with current designs where being on a given bottom 
> serial queue gives you the lock

Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Pierre Habouzit via swift-evolution

-Pierre

> On Sep 2, 2017, at 9:59 PM, Chris Lattner  wrote:
> 
> On Sep 2, 2017, at 12:19 PM, Pierre Habouzit  > wrote:
 What do you mean by this?
>>> 
>>> My understanding is that GCD doesn’t currently scale to 1M concurrent 
>>> queues / tasks.
>> 
>> It completely does provided these 1M queues / tasks are organized on several 
>> well known independent contexts.
> 
> Ok, I stand corrected.  My understanding was that you could run into 
> situations where you get stack explosions, fragment your VM and run out of 
> space, but perhaps that is a relic of 32-bit systems.

a queue on 64bit systems is 128 bytes (nowadays). Provided you have that amount 
of VM available to you (1M queues is 128M after all) then you're good.
If a large amount of them fragments the VM beyond this is a malloc/VM bug on 
64bit systems that are supposed to have enough address space.

> 
 queues are serial/exclusive execution contexts, and if you're not modeling 
 actors as being serial queues, then these two concepts are just disjoint. 
>>> 
>>> AFAICT, the “one queue per actor” model is the only one that makes sense.  
>>> It doesn’t have to be FIFO, but it needs to be some sort of queue.  If you 
>>> allow servicing multiple requests within the actor at a time, then you lose 
>>> the advantages of “no shared mutable state”.
>> 
>> I agree, I don't quite care about how the actor is implemented here, what I 
>> care about is where it runs onto. my wording was poor, what I really meant 
>> is:
>> 
>> queues at the bottom of a queue hierarchy are serial/exclusive execution 
>> contexts, and if you're not modeling actors as being such fully independent 
>> serial queues, then these two concepts are just disjoint.
>> 
>> In GCD there's a very big difference between the one queue at the root of 
>> your graph (just above the thread pool) and any other that is within. The 
>> number that doesn't scale is the number of the former contexts, not the 
>> latter.
> 
> I’m sorry, but I still don’t understand what you’re getting at here.

What doesn't scale is asking for threads, not having queues.

> 
>> The pushback I have here is that today Runloops and dispatch queues on 
>> iOS/macOS are already systems that have huge impedance mismatches, and do 
>> not share the resources either (in terms of OS physical threads). I would 
>> hate for us to bring on ourselves the pain of creating a third completely 
>> different system that is using another way to use threads. When these 3 
>> worlds would interoperate this would cause significant amount of context 
>> switches just to move across the boundaries.
> 
> Agreed, to be clear, I have no objection to building actors on top of 
> (perhaps enhanced) GCD queues.  In fact I *hope* that this can work, since it 
> leads to a naturally more incremental path forward, which is therefore much 
> more likely to actually happen.

Good :)

>> I'd like to dive and debunk this "GCD doesn't scale" point, that I'd almost 
>> call a myth (and I'm relatively unhappy to see these words in your proposal 
>> TBH because they send the wrong message).
> 
> I’m happy to revise the proposal, please let me know what you think makes 
> sense.

What doesn't scale is the way GCD asks for threads, which is what the global 
concurrent queues abstract.
The way it works (or rather limp along) is what we should not reproduce for 
Swift.

What you can write in your proposal and is true is "GCD current relationship 
with the system threads doesn't scale". It's below the queues that the 
scalability has issues.
Dave Z. explained it in a mail earlier today in very good words.

>> My currently not very well formed opinion on this subject is that GCD queues 
>> are just what you need with these possibilities:
>> - this Actor queue can be targeted to other queues by the developer when he 
>> means for these actor to be executed in an existing execution context / 
>> locking domain,
>> - we disallow Actors to be directly targeted to GCD global concurrent queues 
>> ever
>> - for the other ones we create a new abstraction with stronger and better 
>> guarantees (typically limiting the number of possible threads servicing 
>> actors to a low number, not greater than NCPU).
> 
> Is there a specific important use case for being able to target an actor to 
> an existing queue?  Are you looking for advanced patterns where multiple 
> actors (each providing disjoint mutable state) share an underlying queue? 
> Would this be for performance reasons, for compatibility with existing code, 
> or something else?

Mostly for interaction with current designs where being on a given bottom 
serial queue gives you the locking context for resources naturally attached to 
it.

> I don’t see a problem with disallowing actors on the global concurrent queues 
> in general, but I do think it makes sense to be able to provide an 
> abstraction for homing code on the main thread/queue/actor somehow. 
> 
>> I think this 

Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Chris Lattner via swift-evolution
On Sep 2, 2017, at 12:19 PM, Pierre Habouzit  wrote:
>>> What do you mean by this?
>> 
>> My understanding is that GCD doesn’t currently scale to 1M concurrent queues 
>> / tasks.
> 
> It completely does provided these 1M queues / tasks are organized on several 
> well known independent contexts.

Ok, I stand corrected.  My understanding was that you could run into situations 
where you get stack explosions, fragment your VM and run out of space, but 
perhaps that is a relic of 32-bit systems.

>>> queues are serial/exclusive execution contexts, and if you're not modeling 
>>> actors as being serial queues, then these two concepts are just disjoint. 
>> 
>> AFAICT, the “one queue per actor” model is the only one that makes sense.  
>> It doesn’t have to be FIFO, but it needs to be some sort of queue.  If you 
>> allow servicing multiple requests within the actor at a time, then you lose 
>> the advantages of “no shared mutable state”.
> 
> I agree, I don't quite care about how the actor is implemented here, what I 
> care about is where it runs onto. my wording was poor, what I really meant is:
> 
> queues at the bottom of a queue hierarchy are serial/exclusive execution 
> contexts, and if you're not modeling actors as being such fully independent 
> serial queues, then these two concepts are just disjoint.
> 
> In GCD there's a very big difference between the one queue at the root of 
> your graph (just above the thread pool) and any other that is within. The 
> number that doesn't scale is the number of the former contexts, not the 
> latter.

I’m sorry, but I still don’t understand what you’re getting at here.

> The pushback I have here is that today Runloops and dispatch queues on 
> iOS/macOS are already systems that have huge impedance mismatches, and do not 
> share the resources either (in terms of OS physical threads). I would hate 
> for us to bring on ourselves the pain of creating a third completely 
> different system that is using another way to use threads. When these 3 
> worlds would interoperate this would cause significant amount of context 
> switches just to move across the boundaries.

Agreed, to be clear, I have no objection to building actors on top of (perhaps 
enhanced) GCD queues.  In fact I *hope* that this can work, since it leads to a 
naturally more incremental path forward, which is therefore much more likely to 
actually happen.

> I'd like to dive and debunk this "GCD doesn't scale" point, that I'd almost 
> call a myth (and I'm relatively unhappy to see these words in your proposal 
> TBH because they send the wrong message).

I’m happy to revise the proposal, please let me know what you think makes sense.

> My currently not very well formed opinion on this subject is that GCD queues 
> are just what you need with these possibilities:
> - this Actor queue can be targeted to other queues by the developer when he 
> means for these actor to be executed in an existing execution context / 
> locking domain,
> - we disallow Actors to be directly targeted to GCD global concurrent queues 
> ever
> - for the other ones we create a new abstraction with stronger and better 
> guarantees (typically limiting the number of possible threads servicing 
> actors to a low number, not greater than NCPU).

Is there a specific important use case for being able to target an actor to an 
existing queue?  Are you looking for advanced patterns where multiple actors 
(each providing disjoint mutable state) share an underlying queue? Would this 
be for performance reasons, for compatibility with existing code, or something 
else?

I don’t see a problem with disallowing actors on the global concurrent queues 
in general, but I do think it makes sense to be able to provide an abstraction 
for homing code on the main thread/queue/actor somehow. 

> I think this aligns with your idea, in the sense that if you exhaust the 
> Swift Actor Thread Pool, then you're screwed forever. But given that the 
> pattern above can be hidden inside framework code that the developer has *no 
> control over*, it is fairly easy to write actors that eventually through the 
> said framework, would result in this synchronization pattern happening. Even 
> if we can build the amazing debugging tools that make these immediately 
> obvious to the developer (as in understanding what is happening), I don't 
> know how the developer can do *anything* to work around these. The only 
> solution is to fix the frameworks. However the experience of the last few 
> years of maintaining GCD shows that the patterns above are not widely 
> perceived as a dramatic design issue, let alone a bug. It will be a very long 
> road before most framework code there is out there is Swift Actor async/await 
> safe.
> 
> What is your proposal to address this? that we annotate functions that are 
> unsafe? And then, assuming we succeed at this Herculean task, what can 
> developers do anyway about it if the only way to do a thing is async/await 
>

Re: [swift-evolution] Contextualizing async coroutines

2017-09-02 Thread Brent Royal-Gordon via swift-evolution
> On Sep 2, 2017, at 2:56 AM, Pierre Habouzit  wrote:
> 
>> `onResume` hooks seem like a really good way to, essentially, allow 
>> arbitrary concurrency primitives to be passed into `async` functions. My 
>> main question is, if we have it, why do we need coroutine contexts? It seems 
>> to me that anything the coroutine might do with the context could either be 
>> passed into its parameters, or encapsulated in its `onResume` hook.
> 
> No it's not the same. Arbitrary code is this: arbitrary code and data.
> 
> Please read the few mails I sent recently about this, but to recap here 
> quickly:
> 
> It is needed for the runtime (in a broad sense, from language to the 
> operating system) to be able to introspect these:
> - priority attributes
> - dependencies
> - execution contexts (thread/queue/runloop/...)
> - ownership
> 
> Without this info, the scheduling of these coroutines will essentially be 
> random, subject to priority inversions and other similar issues.

I will freely admit that I don't understand all of these details, so in lieu of 
rebutting this, I will simply state what I'm saying more explicitly and ask you 
to explain why I'm wrong in smaller words. :^)

Basically, what I'm saying is: Why do the context details need to be available 
*within the async function*, rather than being available only to the resume 
hook?

For a GCD example, suppose the normal, C-based `dispatch_async` function is 
exposed to Swift as `__dispatch_async`, and `beginAsync` has a signature like 
this:

// I don't think `rethrows` works this way, but pretend it did.
//
/// Starts running an asynchronous function which is started and 
restarted by `resumeHook`.
/// 
/// - Parameter body: The async function to run.
/// - Parameter resumeHook: A function called once for each time `body` 
starts or resumes running. 
/// It is passed a `continuation` function 
representing the next synchronous chunk of 
/// `body`, which it should run (or schedule to 
run). If the `continuation` throws or returns 
/// a non-`nil` value, the function has terminated, 
and the result should be handled 
/// appropriately. If the `continuation` returns 
`nil`, then it has not finished executing.
func beginAsync(do body: () async throws -> Return, 
startingWith resumeHook: @escaping (_ continuation: @escaping () rethrows -> 
Return?) -> Void) { … }

You can then write async-function-handling versions of `async` like:

extension DispatchQueue {
// This version runs a nullary, non-throwing, Void async 
function, and can be called from non-async code.
func async(qos: DispatchQoS = .default, flags: 
DispatchWorkItemFlags = [], execute body: () async -> Void) {
beginAsync(do: body, startingWith: { continuation in
let workItem = DispatchWorkItem(qos: qos, 
flags: flags) {
_ = continuation()
}
__dispatch_async(self, workItem)
})
}

// This version runs any (nullary) async function, and can be 
called from async code.
func async(qos: DispatchQoS = .default, flags: 
DispatchWorkItemFlags = [], execute body: () async throws -> Return) async 
rethrows -> Return {
return try await suspendAsync { successHandler, 
failureHandler in
beginAsync(do: body, startingWith: { 
continuation in
let workItem = DispatchWorkItem(qos: 
qos, flags: flags)  {
do {
if let returnValue = 
try continuation() {

successHandler(returnValue)
}
}
catch {

failureHandler(returnValue)
}
}
__dispatch_async(self, workItem)
})
}
}
}

Information like the QoS is encapsulated by the closure, so that each time it 
enqueues another chunk of work, it attaches that information to it. Is that 
good enough? Or do you need more?

* * *

I *think* you might be saying that, when GCD wants to run a given async block, 
it wants to be able to look ahead to where the `successHandler` will want to 
run so it can schedule the first block on a thread that will be able to 
immediat

Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Andrew Trick via swift-evolution

> On Sep 2, 2017, at 5:34 PM, Xiaodi Wu  wrote:
> 
> On Sat, Sep 2, 2017 at 4:41 PM, Andrew Trick  > wrote:
> 
>> On Sep 2, 2017, at 2:06 PM, Taylor Swift via swift-evolution 
>> mailto:swift-evolution@swift.org>> wrote:
>> 
>> the subscript doesn’t know about the stride that you want to use. If you 
>> want to get rid of the `at:` ambiguity, you have to get rid of it 
>> everywhere, or users will just wind up having to remember two ways (one 
>> ambiguous and one less ambiguous) of doing the same thing, instead of one 
>> (ambiguous) way of doing it.
>> 
>> Certainly, that's a good point. On rethink and another re-reading of the 
>> proposal, it's unclear to me that the addition of `at` arguments to 
>> UnsafeMutablePointer is sufficiently justified by the proposal text. Is it 
>> merely that it's shorter than writing `foo + MemoryLayout.stride * 
>> offset`? With the ambiguity of `at`, it seems that the current way of 
>> writing it, though longer, is certainly less ambiguous. 
>> 
>> Please reread it; UnsafeMutablePointer’s methods do not use `at:`.
> 
> Regarding the typed buffer pointers, I think it is clear by convention, and 
> will be well documented, that the `at` label refers to a position in `self`.
> 
> The raw buffer pointer API isn’t so obvious. Since the `at` refers to `self` 
> it might more logically be a byte offset. Note that `at` as a label name 
> always refers to a strided index.
> 
> This would be a bit more explicit:
> UnsafeRawBufferPointer.initializeMemory(as:T.self, atByteOffset: position * 
> MemoryLayout.stride, from: bufferOfT)
> 
> But possibly less convenient… Since that `at` label currently on 
> UnsafeRawPointer.initializeMemory is almost never used, I don’t think we need 
> to worry too much about convenience.
> 
> That existing `at` label on UnsafeRawPointer.initializeMemory, would also 
> need to be renamed, which is fine.
> 
> If I may suggest one more incremental improvement in clarity, it would be to 
> move `at[ByteOffset]` to be the first argument; this eliminates the possible 
> reading that we are offsetting the source buffer:
> 
> ```
> UnsafeRawBufferPointer.initializeMemory(atByteOffset: position * 
> MemoryLayout.stride, as:T.self, from: bufferOfT)
> ```

Sure, that probably makes sense if we decide to go with a byte offset vs. 
stride index.
-Andy___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Xiaodi Wu via swift-evolution
On Sat, Sep 2, 2017 at 4:41 PM, Andrew Trick  wrote:

>
> On Sep 2, 2017, at 2:06 PM, Taylor Swift via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> the subscript doesn’t know about the stride that you want to use. If you
>>> want to get rid of the `at:` ambiguity, you have to get rid of it
>>> everywhere, or users will just wind up having to remember two ways (one
>>> ambiguous and one less ambiguous) of doing the same thing, instead of one
>>> (ambiguous) way of doing it.
>>>
>>
>> Certainly, that's a good point. On rethink and another re-reading of the
>> proposal, it's unclear to me that the addition of `at` arguments to
>> UnsafeMutablePointer is sufficiently justified by the proposal text. Is it
>> merely that it's shorter than writing `foo + MemoryLayout.stride *
>> offset`? With the ambiguity of `at`, it seems that the current way of
>> writing it, though longer, is certainly less ambiguous.
>>
>
> Please reread it; UnsafeMutablePointer’s methods do *not* use `at:`.
>
>
> Regarding the typed buffer pointers, I think it is clear by convention,
> and will be well documented, that the `at` label refers to a position in
> `self`.
>
> The raw buffer pointer API isn’t so obvious. Since the `at` refers to
> `self` it might more logically be a byte offset. Note that `at` as a label
> name always refers to a strided index.
>
> This would be a bit more explicit:
> UnsafeRawBufferPointer.initializeMemory(as:T.self, atByteOffset: position
> * MemoryLayout.stride, from: bufferOfT)
>
> But possibly less convenient… Since that `at` label currently on
> UnsafeRawPointer.initializeMemory is almost never used, I don’t think we
> need to worry too much about convenience.
>
> That existing `at` label on UnsafeRawPointer.initializeMemory, would also
> need to be renamed, which is fine.
>

If I may suggest one more incremental improvement in clarity, it would be
to move `at[ByteOffset]` to be the first argument; this eliminates the
possible reading that we are offsetting the source buffer:

```
UnsafeRawBufferPointer.initializeMemory(atByteOffset: position *
MemoryLayout.stride, as:T.self, from: bufferOfT)
```
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Pierre Habouzit via swift-evolution
> On Sep 2, 2017, at 2:19 PM, Charles Srstka via swift-evolution 
>  wrote:
> 
>> On Sep 2, 2017, at 4:05 PM, David Zarzycki via swift-evolution 
>> mailto:swift-evolution@swift.org>> wrote:
>> 
>>> On Sep 2, 2017, at 14:15, Chris Lattner via swift-evolution 
>>> mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> My understanding is that GCD doesn’t currently scale to 1M concurrent 
>>> queues / tasks.
>> 
>> Hi Chris!
>> 
>> [As a preface, I’ve only read a few of these concurrency related emails on 
>> swift-evolution, so please forgive me if I missed something.]
>> 
>> When it comes to GCD scalability, the short answer is that millions of of 
>> tiny heap allocations are cheap, be they queues or closures. And GCD has 
>> fairly linear performance so long as the millions of closures/queues are 
>> non-blocking.
>> 
>> The real world is far messier though. In practice, real world code blocks 
>> all of the time. In the case of GCD tasks, this is often tolerable for most 
>> apps, because their CPU usage is bursty and any accidental “thread 
>> explosion” that is created is super temporary. That being said, programs 
>> that create thousands of queues/closures that block on I/O will naturally 
>> get thousands of threads. GCD is efficient but not magic.
>> 
>> As an aside, there are things that future versions of GCD could do to 
>> minimize the “thread explosion” problem. For example, if GCD interposed the 
>> system call layer, it would gain visibility into *why* threads are stalled 
>> and therefore GCD could 1) be more conservative about when to fire up more 
>> worker threads and 2) defer resuming threads that are at “safe” stopping 
>> points if all of the CPUs are busy.
>> 
>> That being done though, the complaining would just shift. Instead of an 
>> “explosion of threads”, people would complain about an “explosion of stacks" 
>> that consume memory and address space. While I and others have argued in the 
>> past that solving this means that frameworks must embrace callback API 
>> design patterns, I personally am no longer of this opinion. As I see it, I 
>> don’t think the complexity (and bugs) of heavy async/callback/coroutine 
>> designs are worth the memory savings. Said differently, the stack is simple 
>> and efficient. Why fight it?
>> 
>> I think the real problem is that programmers cannot pretend that resources 
>> are infinite. For example, if one implements a photo library browsing app, 
>> it would be naive to try and load every image at launch (async or 
>> otherwise). That just won’t scale and that isn’t the operating system's 
>> fault.
> 
> Problems like thread explosion can be solved using higher-level constructs, 
> though. For example, (NS)OperationQueue has a .maxConcurrentOperationCount 
> property. If you make a global OperationQueue, set the maximum to whatever 
> you want it to be, and run all your “primitive” operations through the queue, 
> you can manage the thread count rather effectively.
> 
> I have a few custom Operation subclasses that easily wrap arbitrary 
> asynchronous operations as Operation objects; once the new async/await API 
> comes out, I plan to adapt my subclass to support it, and I’d be happy to 
> submit the code to swift-evolution if people are interested.

NSOperation has several implementation issues, and using it to encapsulate 
asynchronous work means that you don't get the correct priorities (I don't say 
it cant' be fixed, I honnestly don't know, I just know from the mouth of the 
maintainer that NSOperation makes only guarantees if you do all your work from 
-[NSOperation main]).

Second, what Dave is saying is exactly the opposite of what you just wrote. If 
you use NSOQ's maximum concurrency bit, and you throw an infinite amount of 
work at it, *sure* the thread explosion will be fixed but:
- cancelation is a problem
- scalability is a problem
- memory growth is a problem.

The better design is to have a system that works like this:

(1) have a scheduler that knows how many operations are in flight and admits 
two levels "low" and "high".
(2) when you submit work to the scheduler, it tells you if it could take it or 
not, if not, then it's up to you to serialize it somewhere "for later" or 
propagate the error to your client
(3) the scheduler admits up to "high" work items, and as they finish, if you 
reach "low", then you use some notification mechanism to feed it again (and 
possibly get it from the database).

This is how any OS construct works for resource reasons (network sockets, file 
descriptors, ...) where the notification mechanism that writing to these is 
available again is select/poll/epoll/kevent/... name it.

By doing it this way, you actually can write smarter policies on what the next 
work is, because computing what you should do next is usually relatively 
expensive, especially if work comes in all the time and that your decision can 
go stale quickly or that priorities are live. by batching it because the 
scheduler will 

Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Andrew Trick via swift-evolution

> On Sep 2, 2017, at 2:06 PM, Taylor Swift via swift-evolution 
>  wrote:
> 
> the subscript doesn’t know about the stride that you want to use. If you want 
> to get rid of the `at:` ambiguity, you have to get rid of it everywhere, or 
> users will just wind up having to remember two ways (one ambiguous and one 
> less ambiguous) of doing the same thing, instead of one (ambiguous) way of 
> doing it.
> 
> Certainly, that's a good point. On rethink and another re-reading of the 
> proposal, it's unclear to me that the addition of `at` arguments to 
> UnsafeMutablePointer is sufficiently justified by the proposal text. Is it 
> merely that it's shorter than writing `foo + MemoryLayout.stride * 
> offset`? With the ambiguity of `at`, it seems that the current way of writing 
> it, though longer, is certainly less ambiguous. 
> 
> Please reread it; UnsafeMutablePointer’s methods do not use `at:`.

Regarding the typed buffer pointers, I think it is clear by convention, and 
will be well documented, that the `at` label refers to a position in `self`.

The raw buffer pointer API isn’t so obvious. Since the `at` refers to `self` it 
might more logically be a byte offset. Note that `at` as a label name always 
refers to a strided index.

This would be a bit more explicit:
UnsafeRawBufferPointer.initializeMemory(as:T.self, atByteOffset: position * 
MemoryLayout.stride, from: bufferOfT)

But possibly less convenient… Since that `at` label currently on 
UnsafeRawPointer.initializeMemory is almost never used, I don’t think we need 
to worry too much about convenience.

That existing `at` label on UnsafeRawPointer.initializeMemory, would also need 
to be renamed, which is fine.

-Andy___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Xiaodi Wu via swift-evolution
On Sat, Sep 2, 2017 at 4:06 PM, Taylor Swift  wrote:

>
>
> On Sat, Sep 2, 2017 at 3:39 PM, Xiaodi Wu  wrote:
>
>> On Sat, Sep 2, 2017 at 2:13 PM, Taylor Swift 
>> wrote:
>>
>>>
>>>
>>> On Sat, Sep 2, 2017 at 10:03 AM, Xiaodi Wu via swift-evolution <
>>> swift-evolution@swift.org> wrote:
>>>
 On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution <
 swift-evolution@swift.org> wrote:

> Hello Swift community,
>
> The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add
> missing methods, adjust existing labels for clarity, and remove
> deallocation size" begins now and runs through September 7, 2017. The
> proposal is available here:
>
> https://github.com/apple/swift-evolution/blob/master/proposa
> ls/0184-unsafe-pointers-add-missing.md
>
> Reviews are an important part of the Swift evolution process. All
> reviews should be sent to the swift-evolution mailing list at
>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> or, if you would like to keep your feedback private, directly to the
> review manager. When replying, please try to keep the proposal link at the
> top of the message:
>
> Proposal link:
>
> https://github.com/apple/swift-evolution/blob/master/proposa
> ls/0184-unsafe-pointers-add-missing.md
>
> Reply text
>
> Other replies
>
>
> What
> goes into a review?
>
> The goal of the review process is to improve the proposal under review
> through constructive criticism and, eventually, determine the direction of
> Swift. When writing your review, here are some questions you might want to
> answer in your review:
>
>- What is your evaluation of the proposal?
>
> Overall, this is an improvement. However, I do have some questions and
 concerns:


 Questions:

 ## UnsafeMutableRawPointer

 Regarding the options given for "whose `count` to use"--which option is
 actually being proposed?

>>>
>>> I don’t understand the question,, `UnsafeMutableRawPointer` takes an
>>> explicit `count:`. the “whose count to use” option is irrelevant.
>>>
>>
>> In "Proposed Solution," under subheading "UnsafeMutableRawPointer," you
>> write "the question of whose `count` to use becomes important." You then
>> outline "[o]ne option" as well as "[a] better option." Which of these
>> options are you actually proposing? For clarity, could you please excise
>> the non-proposed option from the "Proposed Solution" section and move it to
>> the "Alternatives Considered" section?
>>
>
> The *Proposed solution* section is divided into two parts, one dealing
> with plain pointers and one dealing with buffer pointers. The sections are
> separated by the horizontal rule above “*Buffer pointers are conceptually
> similar…*”. I don’t know why we’re arguing over typographic formatting
> but I am glad this proposal is noncontroversial enough to induce debate
> over its horizontal rules. As for the two options, the first is a strawman
> to explain why we are going with the second option.
>

I am not arguing over formatting. I'm only asking for clarification as to
which of two options, listed in contiguous paragraphs without any
intervening or surrounding horizontal rules, is actually being proposed. Am
I correct in understanding that you are proposing that there be a
precondition that `offset + source.count <= destination.count`? I do agree
that this is the superior design. In that case, the text could use some
clarification as to which is the strawman.

## UnsafeMutableBufferPointer

 Please clarify: why are you proposing that the `at:` arguments in
 `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer`
 _should not_ receive default values, but the `at:` arguments in
 `UnsafeMutableRawPointer` _should_ receive a default value of `0`?


>>>  The extant API for `UnsafeMutableRawPointer` already included these
>>> default arguments which seem to be widely used in the stdlib,, the proposal
>>> tries to avoid these kinds of source breakages wherever possible. We avoid
>>> providing the default arguments on buffer pointers because we want the fact
>>> that it takes a *start–length* segment pair to be obvious at the call
>>> site.
>>>
>>
>> Thanks for the clarification; that would be helpful information to put
>> into the proposal text. It is not an intuitive start-length pair, since the
>> `at` refers to an offset of the destination buffer but `count` refers to a
>> length of the source buffer. I appreciate how you separated the proposed
>> new argument `at` and the existing argument `count` in what is currently
>> named `initializeMemory(as:from:count:)`, which helps to reinforce
>> that fact.
>>
>>
>>> Concerns:

 ## UnsafeMutablePointer

 It's alarming that omitting `coun

Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Charles Srstka via swift-evolution
> On Sep 2, 2017, at 4:05 PM, David Zarzycki via swift-evolution 
>  wrote:
> 
>> On Sep 2, 2017, at 14:15, Chris Lattner via swift-evolution 
>> mailto:swift-evolution@swift.org>> wrote:
>> 
>> My understanding is that GCD doesn’t currently scale to 1M concurrent queues 
>> / tasks.
> 
> Hi Chris!
> 
> [As a preface, I’ve only read a few of these concurrency related emails on 
> swift-evolution, so please forgive me if I missed something.]
> 
> When it comes to GCD scalability, the short answer is that millions of of 
> tiny heap allocations are cheap, be they queues or closures. And GCD has 
> fairly linear performance so long as the millions of closures/queues are 
> non-blocking.
> 
> The real world is far messier though. In practice, real world code blocks all 
> of the time. In the case of GCD tasks, this is often tolerable for most apps, 
> because their CPU usage is bursty and any accidental “thread explosion” that 
> is created is super temporary. That being said, programs that create 
> thousands of queues/closures that block on I/O will naturally get thousands 
> of threads. GCD is efficient but not magic.
> 
> As an aside, there are things that future versions of GCD could do to 
> minimize the “thread explosion” problem. For example, if GCD interposed the 
> system call layer, it would gain visibility into *why* threads are stalled 
> and therefore GCD could 1) be more conservative about when to fire up more 
> worker threads and 2) defer resuming threads that are at “safe” stopping 
> points if all of the CPUs are busy.
> 
> That being done though, the complaining would just shift. Instead of an 
> “explosion of threads”, people would complain about an “explosion of stacks" 
> that consume memory and address space. While I and others have argued in the 
> past that solving this means that frameworks must embrace callback API design 
> patterns, I personally am no longer of this opinion. As I see it, I don’t 
> think the complexity (and bugs) of heavy async/callback/coroutine designs are 
> worth the memory savings. Said differently, the stack is simple and 
> efficient. Why fight it?
> 
> I think the real problem is that programmers cannot pretend that resources 
> are infinite. For example, if one implements a photo library browsing app, it 
> would be naive to try and load every image at launch (async or otherwise). 
> That just won’t scale and that isn’t the operating system's fault.

Problems like thread explosion can be solved using higher-level constructs, 
though. For example, (NS)OperationQueue has a .maxConcurrentOperationCount 
property. If you make a global OperationQueue, set the maximum to whatever you 
want it to be, and run all your “primitive” operations through the queue, you 
can manage the thread count rather effectively.

I have a few custom Operation subclasses that easily wrap arbitrary 
asynchronous operations as Operation objects; once the new async/await API 
comes out, I plan to adapt my subclass to support it, and I’d be happy to 
submit the code to swift-evolution if people are interested.

Charles

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Taylor Swift via swift-evolution
On Sat, Sep 2, 2017 at 3:39 PM, Xiaodi Wu  wrote:

> On Sat, Sep 2, 2017 at 2:13 PM, Taylor Swift  wrote:
>
>>
>>
>> On Sat, Sep 2, 2017 at 10:03 AM, Xiaodi Wu via swift-evolution <
>> swift-evolution@swift.org> wrote:
>>
>>> On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution <
>>> swift-evolution@swift.org> wrote:
>>>
 Hello Swift community,

 The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add
 missing methods, adjust existing labels for clarity, and remove
 deallocation size" begins now and runs through September 7, 2017. The
 proposal is available here:

 https://github.com/apple/swift-evolution/blob/master/proposa
 ls/0184-unsafe-pointers-add-missing.md

 Reviews are an important part of the Swift evolution process. All
 reviews should be sent to the swift-evolution mailing list at

 https://lists.swift.org/mailman/listinfo/swift-evolution

 or, if you would like to keep your feedback private, directly to the
 review manager. When replying, please try to keep the proposal link at the
 top of the message:

 Proposal link:

 https://github.com/apple/swift-evolution/blob/master/proposa
 ls/0184-unsafe-pointers-add-missing.md

 Reply text

 Other replies


 What
 goes into a review?

 The goal of the review process is to improve the proposal under review
 through constructive criticism and, eventually, determine the direction of
 Swift. When writing your review, here are some questions you might want to
 answer in your review:

- What is your evaluation of the proposal?

 Overall, this is an improvement. However, I do have some questions and
>>> concerns:
>>>
>>>
>>> Questions:
>>>
>>> ## UnsafeMutableRawPointer
>>>
>>> Regarding the options given for "whose `count` to use"--which option is
>>> actually being proposed?
>>>
>>
>> I don’t understand the question,, `UnsafeMutableRawPointer` takes an
>> explicit `count:`. the “whose count to use” option is irrelevant.
>>
>
> In "Proposed Solution," under subheading "UnsafeMutableRawPointer," you
> write "the question of whose `count` to use becomes important." You then
> outline "[o]ne option" as well as "[a] better option." Which of these
> options are you actually proposing? For clarity, could you please excise
> the non-proposed option from the "Proposed Solution" section and move it to
> the "Alternatives Considered" section?
>

The *Proposed solution* section is divided into two parts, one dealing with
plain pointers and one dealing with buffer pointers. The sections are
separated by the horizontal rule above “*Buffer pointers are conceptually
similar…*”. I don’t know why we’re arguing over typographic formatting but
I am glad this proposal is noncontroversial enough to induce debate over
its horizontal rules. As for the two options, the first is a strawman to
explain why we are going with the second option.


>
> ## UnsafeMutableBufferPointer
>>>
>>> Please clarify: why are you proposing that the `at:` arguments in
>>> `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer`
>>> _should not_ receive default values, but the `at:` arguments in
>>> `UnsafeMutableRawPointer` _should_ receive a default value of `0`?
>>>
>>>
>>  The extant API for `UnsafeMutableRawPointer` already included these
>> default arguments which seem to be widely used in the stdlib,, the proposal
>> tries to avoid these kinds of source breakages wherever possible. We avoid
>> providing the default arguments on buffer pointers because we want the fact
>> that it takes a *start–length* segment pair to be obvious at the call
>> site.
>>
>
> Thanks for the clarification; that would be helpful information to put
> into the proposal text. It is not an intuitive start-length pair, since the
> `at` refers to an offset of the destination buffer but `count` refers to a
> length of the source buffer. I appreciate how you separated the proposed
> new argument `at` and the existing argument `count` in what is currently
> named `initializeMemory(as:from:count:)`, which helps to reinforce
> that fact.
>
>
>> Concerns:
>>>
>>> ## UnsafeMutablePointer
>>>
>>> It's alarming that omitting `count` in `initialize(repeating:count:)`
>>> (and assign, etc.) means initialize _one_ element, but elsewhere (such as
>>> `UnsafeMutableBufferPointer` means initialize _all_ elements. The behavior
>>> of the proposed API also contradicts its own spelling on its face:
>>> `initialize(repeating: foo)` means *do not repeat* `foo`.
>>>
>>> Yes, I understand the argument that `*BufferPointer` types have an
>>> intrinsic count, etc., but in the context of code where types are inferred,
>>> `let foo = T.allocate(capacity: 100); foo.initialize(repeating: bar)`
>>> should not mean one thing for `*BufferPointer` types and a totally
>>> different thing for

Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread David Zarzycki via swift-evolution

> On Sep 2, 2017, at 14:15, Chris Lattner via swift-evolution 
>  wrote:
> 
> My understanding is that GCD doesn’t currently scale to 1M concurrent queues 
> / tasks.

Hi Chris!

[As a preface, I’ve only read a few of these concurrency related emails on 
swift-evolution, so please forgive me if I missed something.]

When it comes to GCD scalability, the short answer is that millions of of tiny 
heap allocations are cheap, be they queues or closures. And GCD has fairly 
linear performance so long as the millions of closures/queues are non-blocking.

The real world is far messier though. In practice, real world code blocks all 
of the time. In the case of GCD tasks, this is often tolerable for most apps, 
because their CPU usage is bursty and any accidental “thread explosion” that is 
created is super temporary. That being said, programs that create thousands of 
queues/closures that block on I/O will naturally get thousands of threads. GCD 
is efficient but not magic.

As an aside, there are things that future versions of GCD could do to minimize 
the “thread explosion” problem. For example, if GCD interposed the system call 
layer, it would gain visibility into *why* threads are stalled and therefore 
GCD could 1) be more conservative about when to fire up more worker threads and 
2) defer resuming threads that are at “safe” stopping points if all of the CPUs 
are busy.

That being done though, the complaining would just shift. Instead of an 
“explosion of threads”, people would complain about an “explosion of stacks" 
that consume memory and address space. While I and others have argued in the 
past that solving this means that frameworks must embrace callback API design 
patterns, I personally am no longer of this opinion. As I see it, I don’t think 
the complexity (and bugs) of heavy async/callback/coroutine designs are worth 
the memory savings. Said differently, the stack is simple and efficient. Why 
fight it?

I think the real problem is that programmers cannot pretend that resources are 
infinite. For example, if one implements a photo library browsing app, it would 
be naive to try and load every image at launch (async or otherwise). That just 
won’t scale and that isn’t the operating system's fault.

Dave___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Xiaodi Wu via swift-evolution
On Sat, Sep 2, 2017 at 3:36 PM, Andrew Trick  wrote:

> Thanks for the review as always…
>
> On Sep 2, 2017, at 12:13 PM, Taylor Swift via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>
>
> On Sat, Sep 2, 2017 at 10:03 AM, Xiaodi Wu via swift-evolution  evolut...@swift.org> wrote:
>
>> On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution <
>> swift-evolution@swift.org> wrote:
>>
>>> Hello Swift community,
>>>
>>> The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add missing
>>> methods, adjust existing labels for clarity, and remove deallocation size"
>>> begins now and runs through September 7, 2017. The proposal is available
>>> here:
>>>
>>> https://github.com/apple/swift-evolution/blob/master/proposa
>>> ls/0184-unsafe-pointers-add-missing.md
>>>
>>> ## UnsafeMutableBufferPointer
>>
>> Please clarify: why are you proposing that the `at:` arguments in
>> `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` _should
>> not_ receive default values, but the `at:` arguments in
>> `UnsafeMutableRawPointer` _should_ receive a default value of `0`?
>>
>>
>  The extant API for `UnsafeMutableRawPointer` already included these
> default arguments which seem to be widely used in the stdlib,, the proposal
> tries to avoid these kinds of source breakages wherever possible. We avoid
> providing the default arguments on buffer pointers because we want the fact
> that it takes a *start–length* segment pair to be obvious at the call
> site.
>
>
> That’s right, the buffer pointer API is just one level above pointers. It
> primarily offers the safety of tracking its capacity and bounds checking in
> debug mode. It does not help you safely manage fully initialized buffer
> slices (we *do* want to provide that convenience later as a higher-level
> non-pointer type). Instead, it exposes segments within the buffer for
> initialization, assignment, deinitialization. It needs to be obvious in the
> client code, at every call site, that the caller is responsible for
> tracking those segments. Earlier iterations of this proposal attempted to
> hide this as a convenience, but that led to dangerous scenarios.
>
> Taking at Kelvin’s example:
>
> var image = UnsafeMutableBufferPointer.allocate(capacity :
> maxPixels)
>
> var filled:Int = 0
> for scanline: UnsafeMutableBufferPointer in scanlines {
> image.moveInitialize(at: filled, from: scanline)
> filled += scanline.count
> }
> …
> // We don’t want to allow any defaults here.
> // It’s important for the client code to explicitly correlate the range
> // that it initialized with the range that it deinitialized.
> image.deinitialize(at: 0, count: filled)
>
> Concerns:
>>
>> ## UnsafeMutablePointer
>>
>> It's alarming that omitting `count` in `initialize(repeating:count:)`
>> (and assign, etc.) means initialize _one_ element, but elsewhere (such as
>> `UnsafeMutableBufferPointer` means initialize _all_ elements. The behavior
>> of the proposed API also contradicts its own spelling on its face:
>> `initialize(repeating: foo)` means *do not repeat* `foo`.
>>
>> Yes, I understand the argument that `*BufferPointer` types have an
>> intrinsic count, etc., but in the context of code where types are inferred,
>> `let foo = T.allocate(capacity: 100); foo.initialize(repeating: bar)`
>> should not mean one thing for `*BufferPointer` types and a totally
>> different thing for plain `*Pointer` types--particularly when both can be
>> allocated with a certain capacity greater than one.
>>
>> Either `count` should always be required, or for convenience there should
>> be a separate overload `initialize(pointee:)` that does not require `count`.
>>
>>
> I understand the naming is not optimal, but reams of discussion on this
> list have concluded that it’s the least bad alternative available. We can’t
> just get rid of the default value for `count:` because usage in real code
> bases shows that this default argument is actually extremely useful. I
> believe well over 90% of the calls to these methods in the standard library
> currently rely on the default argument value. Renaming the `repeating:`
> argument to `to:` would make the API inconsistent and hide the fact that
> plain pointers are still capable of operating on many elements in sequence
> — “`to:count:`” makes no grammatical sense to read — “to” is a singular
> preposition.
>
>
> The *only* thing I really don’t like about the proposed API is the
> potential confusion between UnsafeMutablePointer calls with a default count
> and UnsafeMutableBufferPointer calls using the implied buffer count. But
> this is where we ended up because the default count turns out to be useful.
> I’m willing to live with it since I don’t see a great alternative.
>

This only thing is also the major thing that causes me concern. I have no
problem with the name itself. In my view, it is important to provide the
very useful function with a default count of 1 using a different name, as
I've written in the other reply

Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Xiaodi Wu via swift-evolution
On Sat, Sep 2, 2017 at 2:13 PM, Taylor Swift  wrote:

>
>
> On Sat, Sep 2, 2017 at 10:03 AM, Xiaodi Wu via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>> On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution <
>> swift-evolution@swift.org> wrote:
>>
>>> Hello Swift community,
>>>
>>> The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add missing
>>> methods, adjust existing labels for clarity, and remove deallocation size"
>>> begins now and runs through September 7, 2017. The proposal is available
>>> here:
>>>
>>> https://github.com/apple/swift-evolution/blob/master/proposa
>>> ls/0184-unsafe-pointers-add-missing.md
>>>
>>> Reviews are an important part of the Swift evolution process. All
>>> reviews should be sent to the swift-evolution mailing list at
>>>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> or, if you would like to keep your feedback private, directly to the
>>> review manager. When replying, please try to keep the proposal link at the
>>> top of the message:
>>>
>>> Proposal link:
>>>
>>> https://github.com/apple/swift-evolution/blob/master/proposa
>>> ls/0184-unsafe-pointers-add-missing.md
>>>
>>> Reply text
>>>
>>> Other replies
>>>
>>>
>>> What
>>> goes into a review?
>>>
>>> The goal of the review process is to improve the proposal under review
>>> through constructive criticism and, eventually, determine the direction of
>>> Swift. When writing your review, here are some questions you might want to
>>> answer in your review:
>>>
>>>- What is your evaluation of the proposal?
>>>
>>> Overall, this is an improvement. However, I do have some questions and
>> concerns:
>>
>>
>> Questions:
>>
>> ## UnsafeMutableRawPointer
>>
>> Regarding the options given for "whose `count` to use"--which option is
>> actually being proposed?
>>
>
> I don’t understand the question,, `UnsafeMutableRawPointer` takes an
> explicit `count:`. the “whose count to use” option is irrelevant.
>

In "Proposed Solution," under subheading "UnsafeMutableRawPointer," you
write "the question of whose `count` to use becomes important." You then
outline "[o]ne option" as well as "[a] better option." Which of these
options are you actually proposing? For clarity, could you please excise
the non-proposed option from the "Proposed Solution" section and move it to
the "Alternatives Considered" section?

## UnsafeMutableBufferPointer
>>
>> Please clarify: why are you proposing that the `at:` arguments in
>> `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` _should
>> not_ receive default values, but the `at:` arguments in
>> `UnsafeMutableRawPointer` _should_ receive a default value of `0`?
>>
>>
>  The extant API for `UnsafeMutableRawPointer` already included these
> default arguments which seem to be widely used in the stdlib,, the proposal
> tries to avoid these kinds of source breakages wherever possible. We avoid
> providing the default arguments on buffer pointers because we want the fact
> that it takes a *start–length* segment pair to be obvious at the call
> site.
>

Thanks for the clarification; that would be helpful information to put into
the proposal text. It is not an intuitive start-length pair, since the `at`
refers to an offset of the destination buffer but `count` refers to a
length of the source buffer. I appreciate how you separated the proposed
new argument `at` and the existing argument `count` in what is currently
named `initializeMemory(as:from:count:)`, which helps to reinforce that
fact.


> Concerns:
>>
>> ## UnsafeMutablePointer
>>
>> It's alarming that omitting `count` in `initialize(repeating:count:)`
>> (and assign, etc.) means initialize _one_ element, but elsewhere (such as
>> `UnsafeMutableBufferPointer` means initialize _all_ elements. The behavior
>> of the proposed API also contradicts its own spelling on its face:
>> `initialize(repeating: foo)` means *do not repeat* `foo`.
>>
>> Yes, I understand the argument that `*BufferPointer` types have an
>> intrinsic count, etc., but in the context of code where types are inferred,
>> `let foo = T.allocate(capacity: 100); foo.initialize(repeating: bar)`
>> should not mean one thing for `*BufferPointer` types and a totally
>> different thing for plain `*Pointer` types--particularly when both can be
>> allocated with a certain capacity greater than one.
>>
>> Either `count` should always be required, or for convenience there should
>> be a separate overload `initialize(pointee:)` that does not require `count`.
>>
>>
> I understand the naming is not optimal, but reams of discussion on this
> list have concluded that it’s the least bad alternative available. We can’t
> just get rid of the default value for `count:` because usage in real code
> bases shows that this default argument is actually extremely useful. I
> believe well over 90% of the calls to these methods in the standard library
> currently rely o

Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Andrew Trick via swift-evolution
Thanks for the review as always…

> On Sep 2, 2017, at 12:13 PM, Taylor Swift via swift-evolution 
>  wrote:
> 
> 
> 
> On Sat, Sep 2, 2017 at 10:03 AM, Xiaodi Wu via swift-evolution 
> mailto:swift-evolution@swift.org>> wrote:
> On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution 
> mailto:swift-evolution@swift.org>> wrote:
> Hello Swift community,
> 
> The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add missing 
> methods, adjust existing labels for clarity, and remove deallocation size" 
> begins now and runs through September 7, 2017. The proposal is available here:
> 
> https://github.com/apple/swift-evolution/blob/master/proposals/0184-unsafe-pointers-add-missing.md
>  
> 
> ## UnsafeMutableBufferPointer
> 
> Please clarify: why are you proposing that the `at:` arguments in 
> `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` _should not_ 
> receive default values, but the `at:` arguments in `UnsafeMutableRawPointer` 
> _should_ receive a default value of `0`?
> 
> 
>  The extant API for `UnsafeMutableRawPointer` already included these default 
> arguments which seem to be widely used in the stdlib,, the proposal tries to 
> avoid these kinds of source breakages wherever possible. We avoid providing 
> the default arguments on buffer pointers because we want the fact that it 
> takes a start–length segment pair to be obvious at the call site.

That’s right, the buffer pointer API is just one level above pointers. It 
primarily offers the safety of tracking its capacity and bounds checking in 
debug mode. It does not help you safely manage fully initialized buffer slices 
(we *do* want to provide that convenience later as a higher-level non-pointer 
type). Instead, it exposes segments within the buffer for initialization, 
assignment, deinitialization. It needs to be obvious in the client code, at 
every call site, that the caller is responsible for tracking those segments. 
Earlier iterations of this proposal attempted to hide this as a convenience, 
but that led to dangerous scenarios.

Taking at Kelvin’s example:

var image = UnsafeMutableBufferPointer.allocate(capacity : maxPixels)

var filled:Int = 0
for scanline: UnsafeMutableBufferPointer in scanlines {
image.moveInitialize(at: filled, from: scanline)
filled += scanline.count
}
…
// We don’t want to allow any defaults here.
// It’s important for the client code to explicitly correlate the range
// that it initialized with the range that it deinitialized.
image.deinitialize(at: 0, count: filled) 

> Concerns:
> 
> ## UnsafeMutablePointer
> 
> It's alarming that omitting `count` in `initialize(repeating:count:)` (and 
> assign, etc.) means initialize _one_ element, but elsewhere (such as 
> `UnsafeMutableBufferPointer` means initialize _all_ elements. The behavior of 
> the proposed API also contradicts its own spelling on its face: 
> `initialize(repeating: foo)` means *do not repeat* `foo`.
> 
> Yes, I understand the argument that `*BufferPointer` types have an intrinsic 
> count, etc., but in the context of code where types are inferred, `let foo = 
> T.allocate(capacity: 100); foo.initialize(repeating: bar)` should not mean 
> one thing for `*BufferPointer` types and a totally different thing for plain 
> `*Pointer` types--particularly when both can be allocated with a certain 
> capacity greater than one.
> 
> Either `count` should always be required, or for convenience there should be 
> a separate overload `initialize(pointee:)` that does not require `count`.
> 
> 
> I understand the naming is not optimal, but reams of discussion on this list 
> have concluded that it’s the least bad alternative available. We can’t just 
> get rid of the default value for `count:` because usage in real code bases 
> shows that this default argument is actually extremely useful. I believe well 
> over 90% of the calls to these methods in the standard library currently rely 
> on the default argument value. Renaming the `repeating:` argument to `to:` 
> would make the API inconsistent and hide the fact that plain pointers are 
> still capable of operating on many elements in sequence — “`to:count:`” makes 
> no grammatical sense to read — “to” is a singular preposition.

The *only* thing I really don’t like about the proposed API is the potential 
confusion between UnsafeMutablePointer calls with a default count and 
UnsafeMutableBufferPointer calls using the implied buffer count. But this is 
where we ended up because the default count turns out to be useful. I’m willing 
to live with it since I don’t see a great alternative.

> 
> ## UnsafeMutableRawBufferPointer
> 
> In `copyBytes`, the use of `Bytes` to emphasize that it's the memory that's 
> being copied is thoughtful, but it is inconsistent with the other method 
> names that use the terminology `Memory` for the same purpose (e.g., 
> `moveInitializeMem

Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread John McCall via swift-evolution

> On Sep 2, 2017, at 3:19 PM, Pierre Habouzit via swift-evolution 
>  wrote:
> 
>> On Sep 2, 2017, at 11:15 AM, Chris Lattner > > wrote:
>> 
>> On Aug 31, 2017, at 7:24 PM, Pierre Habouzit > > wrote:
>>> 
>>> I fail at Finding the initial mail and am quite late to the party of 
>>> commenters, but there are parts I don't undertsand or have questions about.
>>> 
>>> Scalable Runtime
>>> 
>>> [...]
>>> 
>>> The one problem I anticipate with GCD is that it doesn't scale well enough: 
>>> server developers in particular will want to instantiate hundreds of 
>>> thousands of actors in their application, at least one for every incoming 
>>> network connection. The programming model is substantially harmed when you 
>>> have to be afraid of creating too many actors: you have to start 
>>> aggregating logically distinct stuff together to reduce # queues, which 
>>> leads to complexity and loses some of the advantages of data isolation.
>>> 
>>> 
>>> What do you mean by this?
>> 
>> My understanding is that GCD doesn’t currently scale to 1M concurrent queues 
>> / tasks.
> 
> It completely does provided these 1M queues / tasks are organized on several 
> well known independent contexts.
> The place where GCD "fails" at is that if you target your individual serial 
> queues to the global concurrent queues (a.k.a. root queues) which means 
> "please pool, do your job", then yes it doesn't scale, because we take these 
> individual serial queues as proxies for OS threads.
> 
> If however you target these queues to either:
> - new serial queues to segregate your actors per subsystem yourself
> - or some more constrained pool than what the current GCD runtime offers 
> (where we don't create threads to run your work nearly as eagerly)
> 
> Then I don't see why the current implementation of GCD wouldn't scale.

More importantly, the basic interface of GCD doesn't seem to prevent an 
implementation from scaling to fill the resource constraints of a machine.   
The interface to dispatch queues does not imply any substantial persistent 
state besides the task queue itself, and tasks have pretty minimal quiescent 
storage requirements.  Queue-hopping is an unfortunate overhead, but a 
constant-time overhead doesn't really damage scalability and can be addressed 
without a major overhaul of the basic runtime interface.  OS threads can be 
blocked by tasks, but that's not a Dispatch-specific problem, and any solution 
that would fix it in other runtimes would equally fix it in Dispatch.

Now, an arbitrarily-scaling concurrent system is probably a system that's 
destined to eventually become distributed, and there's a strong argument that 
unbounded queues are an architectural mistake in a distributed system: instead, 
every channel of communication should have an opportunity to refuse further 
work, and the entire system should be architected to handle such failures 
gracefully.  But I think that can be implemented reasonably on top of a runtime 
where most local queues are still unbounded and "optimistic".

John.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Pierre Habouzit via swift-evolution
> On Sep 2, 2017, at 11:15 AM, Chris Lattner  wrote:
> 
> On Aug 31, 2017, at 7:24 PM, Pierre Habouzit  > wrote:
>> 
>> I fail at Finding the initial mail and am quite late to the party of 
>> commenters, but there are parts I don't undertsand or have questions about.
>> 
>> Scalable Runtime
>> 
>> [...]
>> 
>> The one problem I anticipate with GCD is that it doesn't scale well enough: 
>> server developers in particular will want to instantiate hundreds of 
>> thousands of actors in their application, at least one for every incoming 
>> network connection. The programming model is substantially harmed when you 
>> have to be afraid of creating too many actors: you have to start aggregating 
>> logically distinct stuff together to reduce # queues, which leads to 
>> complexity and loses some of the advantages of data isolation.
>> 
>> 
>> What do you mean by this?
> 
> My understanding is that GCD doesn’t currently scale to 1M concurrent queues 
> / tasks.

It completely does provided these 1M queues / tasks are organized on several 
well known independent contexts.
The place where GCD "fails" at is that if you target your individual serial 
queues to the global concurrent queues (a.k.a. root queues) which means "please 
pool, do your job", then yes it doesn't scale, because we take these individual 
serial queues as proxies for OS threads.

If however you target these queues to either:
- new serial queues to segregate your actors per subsystem yourself
- or some more constrained pool than what the current GCD runtime offers (where 
we don't create threads to run your work nearly as eagerly)

Then I don't see why the current implementation of GCD wouldn't scale.

> 
>> queues are serial/exclusive execution contexts, and if you're not modeling 
>> actors as being serial queues, then these two concepts are just disjoint. 
> 
> AFAICT, the “one queue per actor” model is the only one that makes sense.  It 
> doesn’t have to be FIFO, but it needs to be some sort of queue.  If you allow 
> servicing multiple requests within the actor at a time, then you lose the 
> advantages of “no shared mutable state”.

I agree, I don't quite care about how the actor is implemented here, what I 
care about is where it runs onto. my wording was poor, what I really meant is:

queues at the bottom of a queue hierarchy are serial/exclusive execution 
contexts, and if you're not modeling actors as being such fully independent 
serial queues, then these two concepts are just disjoint.

In GCD there's a very big difference between the one queue at the root of your 
graph (just above the thread pool) and any other that is within. The number 
that doesn't scale is the number of the former contexts, not the latter.

The pushback I have here is that today Runloops and dispatch queues on 
iOS/macOS are already systems that have huge impedance mismatches, and do not 
share the resources either (in terms of OS physical threads). I would hate for 
us to bring on ourselves the pain of creating a third completely different 
system that is using another way to use threads. When these 3 worlds would 
interoperate this would cause significant amount of context switches just to 
move across the boundaries.

"GCD Doesn't scale so let's build something new" will only create pain, we need 
a way for actors to inherently run on a thread pool that is shared with 
dispatch and that dispatch can reason about and vice versa, and where the Swift 
runtime gives enough information for GCD for it to execute the right work at 
the right time.

I'd like to dive and debunk this "GCD doesn't scale" point, that I'd almost 
call a myth (and I'm relatively unhappy to see these words in your proposal TBH 
because they send the wrong message).

Way before I started working on it, probably to ease adoption, the decision was 
made that it was ok to write code such as this and have it run without problems 
(FSVO without problems):

dispatch_queue_t q = ...;
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_async(q, ^{ dispatch_semaphore_signal(sema); });
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);


To accommodate for this we when the caller of this code blocks a worker thread, 
then the kernel will notice your level of concurrency dropped and will bring up 
a new thread for you. This thread will likely be the one that picks up `q` that 
got woken up by this async, and will unblock the caller.

If you never write such horrible code, then GCD scales *just fine*. The real 
problem is that if you go async you need to be async all the way. Node.js and 
other similar projects have understood that a very long time ago. If you 
express dependencies between asynchronous execution context with a blocking 
relationship such as above, then you're just committing performance suicide. 
GCD handles this by adding more threads and overcommitting the system, my 
understanding is that your proposal is to instead livelock.



My curr

Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Taylor Swift via swift-evolution
On Sat, Sep 2, 2017 at 10:03 AM, Xiaodi Wu via swift-evolution <
swift-evolution@swift.org> wrote:

> On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>> Hello Swift community,
>>
>> The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add missing
>> methods, adjust existing labels for clarity, and remove deallocation size"
>> begins now and runs through September 7, 2017. The proposal is available
>> here:
>>
>> https://github.com/apple/swift-evolution/blob/master/proposa
>> ls/0184-unsafe-pointers-add-missing.md
>>
>> Reviews are an important part of the Swift evolution process. All reviews
>> should be sent to the swift-evolution mailing list at
>>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> or, if you would like to keep your feedback private, directly to the
>> review manager. When replying, please try to keep the proposal link at the
>> top of the message:
>>
>> Proposal link:
>>
>> https://github.com/apple/swift-evolution/blob/master/proposa
>> ls/0184-unsafe-pointers-add-missing.md
>>
>> Reply text
>>
>> Other replies
>>
>> What
>> goes into a review?
>>
>> The goal of the review process is to improve the proposal under review
>> through constructive criticism and, eventually, determine the direction of
>> Swift. When writing your review, here are some questions you might want to
>> answer in your review:
>>
>>- What is your evaluation of the proposal?
>>
>> Overall, this is an improvement. However, I do have some questions and
> concerns:
>
>
> Questions:
>
> ## UnsafeMutableRawPointer
>
> Regarding the options given for "whose `count` to use"--which option is
> actually being proposed?
>

I don’t understand the question,, `UnsafeMutableRawPointer` takes an
explicit `count:`. the “whose count to use” option is irrelevant.


>
> ## UnsafeMutableBufferPointer
>
> Please clarify: why are you proposing that the `at:` arguments in
> `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` _should
> not_ receive default values, but the `at:` arguments in
> `UnsafeMutableRawPointer` _should_ receive a default value of `0`?
>
>
 The extant API for `UnsafeMutableRawPointer` already included these
default arguments which seem to be widely used in the stdlib,, the proposal
tries to avoid these kinds of source breakages wherever possible. We avoid
providing the default arguments on buffer pointers because we want the fact
that it takes a *start–length* segment pair to be obvious at the call site.

Concerns:
>
> ## UnsafeMutablePointer
>
> It's alarming that omitting `count` in `initialize(repeating:count:)` (and
> assign, etc.) means initialize _one_ element, but elsewhere (such as
> `UnsafeMutableBufferPointer` means initialize _all_ elements. The behavior
> of the proposed API also contradicts its own spelling on its face:
> `initialize(repeating: foo)` means *do not repeat* `foo`.
>
> Yes, I understand the argument that `*BufferPointer` types have an
> intrinsic count, etc., but in the context of code where types are inferred,
> `let foo = T.allocate(capacity: 100); foo.initialize(repeating: bar)`
> should not mean one thing for `*BufferPointer` types and a totally
> different thing for plain `*Pointer` types--particularly when both can be
> allocated with a certain capacity greater than one.
>
> Either `count` should always be required, or for convenience there should
> be a separate overload `initialize(pointee:)` that does not require `count`.
>
>
I understand the naming is not optimal, but reams of discussion on this
list have concluded that it’s the least bad alternative available. We can’t
just get rid of the default value for `count:` because usage in real code
bases shows that this default argument is actually extremely useful. I
believe well over 90% of the calls to these methods in the standard library
currently rely on the default argument value. Renaming the `repeating:`
argument to `to:` would make the API inconsistent and hide the fact that
plain pointers are still capable of operating on many elements in sequence
— “`to:count:`” makes no grammatical sense to read — “to” is a singular
preposition.


>
> ## UnsafeMutableRawBufferPointer
>
> In `copyBytes`, the use of `Bytes` to emphasize that it's the memory
> that's being copied is thoughtful, but it is inconsistent with the other
> method names that use the terminology `Memory` for the same purpose (e.g.,
> `moveInitializeMemory` to clarify the meaning of `moveInitialize`).
>
> For better consistency--and since you're proposing to rename
> `copyBytes(from:count:)` on `UnsafeMutableRawPointer` to
> `copy(from:bytes:)`--this particular API on `UnsafeMutableRawBufferPointer`
> should be named `copyMemory(from:)` and not `copyBytes(from:)`.
>
> Although, actually, looking at the APIs on `UnsafeMutableRawPointer`
> itself, that particular method too might best be written as
> 

Re: [swift-evolution] Contextualizing async coroutines

2017-09-02 Thread Chris Lattner via swift-evolution
On Aug 31, 2017, at 11:35 AM, Joe Groff via swift-evolution 
 wrote:
> The coroutine proposal as it stands essentially exposes raw delimited 
> continuations. While this is a flexible and expressive feature in the 
> abstract, for the concrete purpose of representing asynchronous coroutines, 
> it provides weak user-level guarantees about where their code might be 
> running after being resumed from suspension, and puts a lot of pressure on 
> APIs to be well-behaved in this respect. And if we're building toward actors, 
> where async actor methods should be guaranteed to run "in the actor", I think 
> we'll *need* something more than the bare-bones delimited continuation 
> approach to get there. I think the proposal's desire to keep coroutines 
> independent of a specific runtime model is a good idea, but I also think 
> there are a couple possible modifications we could add to the design to make 
> it easier to reason about what context things run in for any runtime model 
> that benefits from async/await:
> 
> # Coroutine context
> 
> Associating a context value with a coroutine would let us thread useful 
> information through the execution of the coroutine. This is particularly 
> useful for GCD, so you could attach a queue, QoS, and other attributes to the 
> coroutine, since these aren't reliably available from the global environment. 
> It could be a performance improvement even for things like per-pthread 
> queues, since coroutine context should be cheaper to access than 
> pthread_self. 
> 
> For example, a coroutine-aware `dispatch_async` could spawn a coroutine with 
> the queue object and other interesting attributes as its context:
> 
> extension DispatchQueue {
> func `async`(_ body: () async -> ()) {
>   dispatch_async(self, {
> beginAsync(context: self) { await body() }
>   })
> }
> }

I think it makes perfect sense to add a magically available context to async 
functions, and something like the above is a good way to populate it.  Because 
is is a magic value that is only available in async functions, giving it a 
keyword like asyncContext might make sense.  That said, I don’t understand how 
(by itself) this helps the queue hopping problem.

> # `onResume` hooks
> 
> Relying on coroutine context alone still leaves responsibility wholly on 
> suspending APIs to pay attention to the coroutine context and schedule the 
> continuation correctly. You'd still have the expression problem when 
> coroutine-spawning APIs from one framework interact with suspending APIs from 
> another framework that doesn't understand the spawning framework's desired 
> scheduling policy. We could provide some defense against this by letting the 
> coroutine control its own resumption with an "onResume" hook, which would run 
> when a suspended continuation is invoked instead of immediately resuming the 
> coroutine. That would let the coroutine-aware dispatch_async example from 
> above do something like this, to ensure the continuation always ends up back 
> on the correct queue:

Yes, we need something like this, though I’m not sure how your proposal works:

> extension DispatchQueue {
> func `async`(_ body: () async -> ()) {
>   dispatch_async(self, {
> beginAsync(
>   context: self,
>   body: { await body() },
>   onResume: { continuation in
> // Defensively hop to the right queue
> dispatch_async(self, continuation)

If I’m running on a pthread, and use "someQueue.async {…}”, I don’t see how 
DispatchQueue.async can know how to take me back to a pthread.  If I understand 
your example code above, it looks like the call will run the continuation on 
someQueue instead.

That said, I think that your idea of context pretty much covers it: a non-async 
function cannot have any idea whether it is run on a queue or thread, but there 
is also no language way to call an async function from a non-async function.  I 
think this means that beginAsync and DispatchQueue.async will have to define 
some policy: for example, the implementation of DispatchQueue.async could use 
its own internal data structures to decide if the current task is being run on 
some dispatch queue (using the maligned “give me the current queue” operation), 
and ensure that it returns to the originating queue if it can find one.

Chains of async functions calling each other would maintain their context, so 
the other transitions we have to worry about are when an async function calls a 
non-async function (this just drops the context) or when you get to the bottom 
of the pile of async 🐢’s and want to actually do something on another context.  
This implies you’d actually want an async form of DispatchQueue.async, 
something like this:

extension DispatchQueue {
func `async`(_ body: () async -> ()) async {
  dispatch_async(self) {
beginAsync(
  context: self,
  body: { 
 await body() 
 asyncContext.restore()
  })
  }}

Going back to the silly example, if you call DispatchQueue.a

Re: [swift-evolution] [Concurrency] A slightly different perspective

2017-09-02 Thread Chris Lattner via swift-evolution
On Aug 31, 2017, at 3:04 PM, Nathan Gray via swift-evolution 
 wrote:
> I've been following the conversations around Chris Lattner's intriguing 
> async/await proposal and would like to offer my own take. I feel that the 
> proposal as written is almost perfect.  My suggestions for improving it are 
> not highly original -- I think they have all come up already -- but I'd like 
> to present them from my own perspective.
> 
> 1. Fixing "queue confusion" *must* be part of this proposal.  The key bit of 
> "magic" offered by async/await over continuation passing is that you're 
> working in a single scope.  A single scope should execute on a single queue 
> unless the programmer explicitly requests otherwise.  Queue hopping is a 
> surprising problem in a single scope, and one that there's currently no 
> adequate solution for.

As mentioned downthread, the “contextualizing” thread is one way to address 
this.

> 2. The proposal should include some basic coordination mechanism.  The 
> argument against returning a Future every time `await` is called is 
> convincing, so my suggestion is to do it from `beginAsync`. The Future 
> returned should only be specified by protocol. The protocol can start with 
> minimal features -- perhaps just cancellation and progress.  There should be 
> a way for programmers to specify their own, more featureful, types. (The 
> proposal mentions the idea of returning a Bool, which is perhaps the 
> least-featureful Future type imaginable. :-)

Please don’t read too much into the beginAsync API.  It is merely a strawman, 
and intended to be a low-level API that higher level abstractions (like a 
decent futures API) can be built on top of.  I think it is important to have 
some sort of primitive low-level API that is independent of higher level 
abstractions like Futures.

This is all a way of saying “yes, having something like you propose makes 
sense” but that it should be part of the Futures API, which is outside the 
scope of the async/await proposal.

-Chris

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Concurrency] async/await + actors

2017-09-02 Thread Chris Lattner via swift-evolution
On Aug 31, 2017, at 7:24 PM, Pierre Habouzit  wrote:
> 
> I fail at Finding the initial mail and am quite late to the party of 
> commenters, but there are parts I don't undertsand or have questions about.
> 
> Scalable Runtime
> 
> [...]
> 
> The one problem I anticipate with GCD is that it doesn't scale well enough: 
> server developers in particular will want to instantiate hundreds of 
> thousands of actors in their application, at least one for every incoming 
> network connection. The programming model is substantially harmed when you 
> have to be afraid of creating too many actors: you have to start aggregating 
> logically distinct stuff together to reduce # queues, which leads to 
> complexity and loses some of the advantages of data isolation.
> 
> 
> What do you mean by this?

My understanding is that GCD doesn’t currently scale to 1M concurrent queues / 
tasks.

> queues are serial/exclusive execution contexts, and if you're not modeling 
> actors as being serial queues, then these two concepts are just disjoint.

AFAICT, the “one queue per actor” model is the only one that makes sense.  It 
doesn’t have to be FIFO, but it needs to be some sort of queue.  If you allow 
servicing multiple requests within the actor at a time, then you lose the 
advantages of “no shared mutable state”.

> Actors are the way you present the various tasks/operations/activities that 
> you schedule. These contexts are a way for the developer to explain which 
> things are related in a consistent system, and give them access to state 
> which is local to this context (whether it's TSD for threads, or queue 
> specific data, or any similar context),

Just MHO, but I don’t think you’d need or want the concept of “actor local 
data” in the sense of TLS (e.g. __thread).  All actor methods have a ‘self’ 
already, and having something like TLS strongly encourages breaking the model.  
To me, the motivation for TLS is to provide an easier way to migrate 
single-threaded global variables, when introducing threading into legacy code.

This is not a problem we need or want to solve, given programmers would be 
rewriting their algorithm anyway to get it into the actor model.

> IMO, Swift as a runtime should define what an execution context is, and be 
> relatively oblivious of which context it is exactly as long it presents a few 
> common capabilities:
> - possibility to schedule work (async)
> - have a name
> - be an exclusion context
> - is an entity the kernel can reason about (if you want to be serious about 
> any integration on a real operating system with priority inheritance and 
> complex issues like this, which it is the OS responsibility to handle and not 
> the language)
> - ...
> 
> In that sense, whether your execution context is:
> - a dispatch serial queue
> - a CFRunloop
> - a libev/libevent/... event loop
> - your own hand rolled event loop

Generalizing the approach is completely possible, but it is also possible to 
introduce a language abstraction that is “underneath” the high level event 
loops.  That’s what I’m proposing.

> 
> Design sketch for interprocess and distributed compute
> 
> [...]
> 
> One of these principles is the concept of progressive disclosure of 
> complexity : a Swift 
> developer shouldn't have to worry about IPC or distributed compute if they 
> don't care about it.
> 
> 
> While I agree with the sentiment, I don't think that anything useful can be 
> done without "distributed" computation. I like the loadResourceFromTheWeb 
> example, as we have something like this on our platform, which is the 
> NSURLSession APIs, or the CloudKit API Surface, that are about fetching some 
> resource from a server (URL or CloudKit database records). However, they 
> don't have a single result, they have:
> 
> - progress notification callbacks
> - broken down notifications for the results (e.g. headers first and body 
> second, or per-record for CloudKit operations)
> - various levels of error reporting.

I don’t understand the concern about this.  If you want low level control like 
this, it is quite easy to express that.  However, it is also quite common to 
just want to say “load a URL with this name”, which is super easy and awesome 
with async/await.

> I expect most developers will have to use such a construct, and for these, 
> having a single async pivot in your code that essentially fully serializes 
> your state machine on getting a full result from the previous step to be 
> lacking.

Agreed, the examples are not trying to show that.  It is perfectly fine to pass 
in additional callbacks (or delegates, etc) to async methods, which would be a 
natural way to express this… just like the current APIs do.

> Delivering all these notifications on the context of the initiator would be 
> quite inefficient as clearly there are in my example above two very different 
> contexts, and having to hop through one to reach the other would make thi

Re: [swift-evolution] [Concurrency] Fixing race conditions in async/await example

2017-09-02 Thread Chris Lattner via swift-evolution
On Aug 31, 2017, at 5:48 PM, Pierre Habouzit via swift-evolution 
 wrote:
>> Unlike the proposed future code the async code is not naturally parallel, in 
>> the running example the following lines from the async code are run in 
>> series, i.e. await blocks:
>> 
>>   let dataResource  = await loadWebResource("dataprofile.txt")
>>   let imageResource = await loadWebResource("imagedata.dat")
>> The equivalent lines using the proposed Future:
>>   let dataResource  = loadWebResource("dataprofile.txt")
>>   let imageResource = loadWebResource("imagedata.dat")
>> Run in parallel and therefore are potentially faster assuming that 
>> resources, like cores and IO, are available.
>> 
>> Therefore you would be better using a Future than an async, so why provide 
>> an async unless you can make a convincing argument that it allows you to 
>> write a better future?
> 
> In practice, you would really want all resources that you load from the 
> internet to be handled from the same execution context (whether it's a 
> dispatch queue, a thread or a CFRunloop is absolutely not relevant), because 
> it's very likely that you'll end up contending concurrent executions of these 
> loads through locks and the various shared resources in use (like your NIC 
> and the networking stack).

I completely agree with this point, and this is one of the nice things about 
the model as described: It allows the programmer to describe concurrent 
abstractions that make sense for their app, WITHOUT being bound to how the 
async operations themselves are implemented.  I don’t expect the whole world to 
be reimplemented, but if it was, I’d expect that there would end up being one 
“network card actor” for each physical nic that is present.  No matter how many 
concurrent requests are started by clients, they’d be serially enqueued on the 
actors queue, and the requests would presumably be serviced in parallel using 
efficient shared mutable state WITHIN the network card actor.

> On real systems going wide concurrently is not often a win provided the thing 
> you're doing is complex enough.
> The reason for it is that most of these subsystems, and loadWebResource is a 
> perfect example of this, use constrained resources that use locks and the 
> like.


I agree with you if you’re talking about a single machine, but if you’re 
talking about distributing across a cluster of a thousand machines, then I 
disagree.

-Chris

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE-0184: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

2017-09-02 Thread Xiaodi Wu via swift-evolution
On Sat, Sep 2, 2017 at 12:27 AM, Douglas Gregor via swift-evolution <
swift-evolution@swift.org> wrote:

> Hello Swift community,
>
> The review of SE-0184 "Unsafe[Mutable][Raw][Buffer]Pointer: add missing
> methods, adjust existing labels for clarity, and remove deallocation size"
> begins now and runs through September 7, 2017. The proposal is available
> here:
>
> https://github.com/apple/swift-evolution/blob/master/
> proposals/0184-unsafe-pointers-add-missing.md
>
> Reviews are an important part of the Swift evolution process. All reviews
> should be sent to the swift-evolution mailing list at
>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> or, if you would like to keep your feedback private, directly to the
> review manager. When replying, please try to keep the proposal link at the
> top of the message:
>
> Proposal link:
>
> https://github.com/apple/swift-evolution/blob/master/
> proposals/0184-unsafe-pointers-add-missing.md
>
> Reply text
>
> Other replies
>
> What
> goes into a review?
>
> The goal of the review process is to improve the proposal under review
> through constructive criticism and, eventually, determine the direction of
> Swift. When writing your review, here are some questions you might want to
> answer in your review:
>
>- What is your evaluation of the proposal?
>
> Overall, this is an improvement. However, I do have some questions and
concerns:


Questions:

## UnsafeMutableRawPointer

Regarding the options given for "whose `count` to use"--which option is
actually being proposed?

## UnsafeMutableBufferPointer

Please clarify: why are you proposing that the `at:` arguments in
`UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` _should
not_ receive default values, but the `at:` arguments in
`UnsafeMutableRawPointer` _should_ receive a default value of `0`?


Concerns:

## UnsafeMutablePointer

It's alarming that omitting `count` in `initialize(repeating:count:)` (and
assign, etc.) means initialize _one_ element, but elsewhere (such as
`UnsafeMutableBufferPointer` means initialize _all_ elements. The behavior
of the proposed API also contradicts its own spelling on its face:
`initialize(repeating: foo)` means *do not repeat* `foo`.

Yes, I understand the argument that `*BufferPointer` types have an
intrinsic count, etc., but in the context of code where types are inferred,
`let foo = T.allocate(capacity: 100); foo.initialize(repeating: bar)`
should not mean one thing for `*BufferPointer` types and a totally
different thing for plain `*Pointer` types--particularly when both can be
allocated with a certain capacity greater than one.

Either `count` should always be required, or for convenience there should
be a separate overload `initialize(pointee:)` that does not require `count`.


## UnsafeMutableRawBufferPointer

In `copyBytes`, the use of `Bytes` to emphasize that it's the memory that's
being copied is thoughtful, but it is inconsistent with the other method
names that use the terminology `Memory` for the same purpose (e.g.,
`moveInitializeMemory` to clarify the meaning of `moveInitialize`).

For better consistency--and since you're proposing to rename
`copyBytes(from:count:)` on `UnsafeMutableRawPointer` to
`copy(from:bytes:)`--this particular API on `UnsafeMutableRawBufferPointer`
should be named `copyMemory(from:)` and not `copyBytes(from:)`.

Although, actually, looking at the APIs on `UnsafeMutableRawPointer`
itself, that particular method too might best be written as
`copyMemory(from:bytes:)` instead of merely `copy(from:bytes:)` for better
consistency with the rest of the methods on that type as well.


## General comment

Many `at:` arguments, especially such as in the case of
`copyBytes(at:from:)`, make sense only when read in a list with all other
methods. Standing alone, `at` is ambiguous as to whether it's referring to
the _source_ or the _destination_. Why do these APIs on `*BufferPointer`
types not take advantage of subscripts? That is, why not:

  `foo[x...].copyMemory(from: bar)`

instead of

  `foo.copyBytes(at: x, from: bar)`

The first seems dramatically clearer as to its meaning. The same feedback
applies to nearly all uses of `at` on `*BufferPointer` types: they would
seem to be greatly clarified (in terms of the "what does `at` mean"
question) by the use of a subscript spelling.

I notice that you comment that you feel there are ergonomic issues with
buffer pointer slicing; can you please comment on what is "wasteful"
currently? Is there a performance hit to slicing a `*BufferPointer` type?
If so, we should fix that, as the whole rationale of having these types (as
I understand it) is to improve the ergonomics of working with pointers to
multiple elements by conforming them to `*Collection` APIs.

It seems deeply unsatisfactory to invent new methods that use `at:`
arguments _on a type whose purpose is to expose `*Collection` APIs_ if we
agree that 

Re: [swift-evolution] Contextualizing async coroutines

2017-09-02 Thread Pierre Habouzit via swift-evolution

-Pierre

> On Sep 2, 2017, at 1:58 AM, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
>> On Aug 31, 2017, at 11:35 AM, Joe Groff via swift-evolution 
>>  wrote:
>> 
>> # Coroutine context
>> 
>> # `onResume` hooks
> 
> `onResume` hooks seem like a really good way to, essentially, allow arbitrary 
> concurrency primitives to be passed into `async` functions. My main question 
> is, if we have it, why do we need coroutine contexts? It seems to me that 
> anything the coroutine might do with the context could either be passed into 
> its parameters, or encapsulated in its `onResume` hook.

No it's not the same. Arbitrary code is this: arbitrary code and data.

Please read the few mails I sent recently about this, but to recap here quickly:

It is needed for the runtime (in a broad sense, from language to the operating 
system) to be able to introspect these:
- priority attributes
- dependencies
- execution contexts (thread/queue/runloop/...)
- ownership

Without this info, the scheduling of these coroutines will essentially be 
random, subject to priority inversions and other similar issues.



>> and also prevents writing APIs that intentionally change context across an 
>> `await`, like a theoretical "goToMainThread()" function
> 
> You say that like it's a bad thing. :^)
> 
> (Seriously, I feel like that makes it *way* too easy to jump to another 
> thread in the middle of a function using what looks like an ordinary line of 
> code. A `let result = await someQueue.async { … }` syntax is a lot clearer 
> that you're hopping to another thread and about what code will run on it, but 
> can get around our current "pyramid of doom" problem. If the async syntax 
> guarantees that the code before and after the `await` runs in the same 
> "environment"—whatever environment is set up by the onResume hook—then that 
> makes async functions much safer and easier for programmers to reason about, 
> while only restricting their power slightly.)

I do agree that an explicit syntax that spells out the context when it changes 
is really preferable, and if no context is provided it should mean "the current 
one".
The context doesn't necessarily need to be a dispatch queue.

Ideally API surface that provide similar things could be annotated for Swift to 
reason about, e.g. to take a realatively obvious example:

void xpc_connection_send_message_with_reply(xpc_connection_t conn, 
xpc_object_t msg, dispatch_queue_t queue, void (^handler)(xpc_object_t reply))

Could provided sufficient overlay, could be understood by Swift and provide 
something like this (completely random syntax, I barely do any Swift, so bear 
with me):

let reply = await(queue) connection.sendQuery(message: msg)

Because the API could be annotated with `queue` in that function is the 
execution context for the coroutine, and `handler` is the said coroutine.


-Pierre___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Contextualizing async coroutines

2017-09-02 Thread Brent Royal-Gordon via swift-evolution
> On Aug 31, 2017, at 11:35 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> # Coroutine context
> 
> # `onResume` hooks

`onResume` hooks seem like a really good way to, essentially, allow arbitrary 
concurrency primitives to be passed into `async` functions. My main question 
is, if we have it, why do we need coroutine contexts? It seems to me that 
anything the coroutine might do with the context could either be passed into 
its parameters, or encapsulated in its `onResume` hook.

> and also prevents writing APIs that intentionally change context across an 
> `await`, like a theoretical "goToMainThread()" function

You say that like it's a bad thing. :^)

(Seriously, I feel like that makes it *way* too easy to jump to another thread 
in the middle of a function using what looks like an ordinary line of code. A 
`let result = await someQueue.async { … }` syntax is a lot clearer that you're 
hopping to another thread and about what code will run on it, but can get 
around our current "pyramid of doom" problem. If the async syntax guarantees 
that the code before and after the `await` runs in the same 
"environment"—whatever environment is set up by the onResume hook—then that 
makes async functions much safer and easier for programmers to reason about, 
while only restricting their power slightly.)

-- 
Brent Royal-Gordon
Architechies

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Why you can't make someone else's class Decodable: a long-winded explanation of 'required' initializers

2017-09-02 Thread Fabian Ehrentraud via swift-evolution

Am 03.08.2017 um 02:09 schrieb Jordan Rose via swift-evolution 
mailto:swift-evolution@swift.org>>:

David Hart recently asked on 
Twitter if there was a 
good way to add Decodable support to somebody else's class. The short answer is 
"no, because you don't control all the subclasses", but David already 
understood that and wanted to know if there was anything working to mitigate 
the problem. So I decided to write up a long email about it instead. (Well, 
actually I decided to write a short email and then failed at doing so.)

The Problem

You can add Decodable to someone else's struct today with no problems:

extension Point: Decodable {
  enum CodingKeys: String, CodingKey {
case x
case y
  }
  public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let x = try container.decode(Double.self, forKey: .x)
let y = try container.decode(Double.self, forKey: .y)
self.init(x: x, y: y)
  }
}

But if Point is a (non-final) class, then this gives you a pile of errors:

- init(from:) needs to be 'required' to satisfy a protocol requirement. 
'required' means the initializer can be invoked dynamically on subclasses. Why 
is this important? Because someone might write code like this:

func decodeMe() -> Result {
  let decoder = getDecoderFromSomewhere()
  return Result(from: decoder)
}
let specialPoint: VerySpecialSubclassOfPoint = decodeMe()

…and the compiler can't stop them, because VerySpecialSubclassOfPoint is a 
Point, and Point is Decodable, and therefore VerySpecialSubclassOfPoint is 
Decodable. A bit more on this later, but for now let's say that's a sensible 
requirement.

- init(from:) also has to be a 'convenience' initializer. That one makes sense 
too—if you're outside the module, you can't necessarily see private properties, 
and so of course you'll have to call another initializer that can.

But once it's marked 'convenience' and 'required' we get "'required' 
initializer must be declared directly in class 'Point' (not in an extension)", 
and that defeats the whole purpose. Why this restriction?


The Semantic Reason

The initializer is 'required', right? So all subclasses need to have access to 
it. But the implementation we provided here might not make sense for all 
subclasses—what if VerySpecialSubclassOfPoint doesn't have an 'init(x:y:)' 
initializer? Normally, the compiler checks for this situation and makes the 
subclass reimplement the 'required' initializer…but that only works if the 
'required' initializers are all known up front. So it can't allow this new 
'required' initializer to go by, because someone might try to call it 
dynamically on a subclass. Here's a dynamic version of the code from above:

func decodeDynamic(_ pointType: Point.Type) -> Point {
  let decoder = getDecoderFromSomewhere()
  return pointType.init(from: decoder)
}
let specialPoint = decodeDynamic(VerySpecialSubclassOfPoint.self)


The Implementation Reason

'required' initializers are like methods: they may require dynamic dispatch. 
That means that they get an entry in the class's dynamic dispatch table, 
commonly known as its vtable. Unlike Objective-C method tables, vtables aren't 
set up to have entries arbitrarily added at run time.

(Aside: This is one of the reasons why non-@objc methods in Swift extensions 
can't be overridden; if we ever lift that restriction, it'll be by using a 
separate table and a form of dispatch similar to objc_msgSend. I sent a 
proposal to swift-evolution about this last year but there wasn't much 
interest.)


The Workaround

Today's answer isn't wonderful, but it does work: write a wrapper struct that 
conforms to Decodable instead:

struct DecodedPoint: Decodable {
  var value: Point
  enum CodingKeys: String, CodingKey {
case x
case y
  }
  public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let x = try container.decode(Double.self, forKey: .x)
let y = try container.decode(Double.self, forKey: .y)
self.value = Point(x: x, y: y)
  }
}

This doesn't have any of the problems with inheritance, because it only handles 
the base class, Point. But it makes everywhere else a little less 
convenient—instead of directly encoding or decoding Point, you have to use the 
wrapper, and that means no implicitly-generated Codable implementations either.

I'm not going to spend more time talking about this, but it is the officially 
recommended answer at the moment. You can also just have all your own types 
that contain points manually decode the 'x' and 'y' values and then construct a 
Point from that.


Future Direction: 'required' + 'final'

One language feature we could add to make this work is a 'required' initializer 
that is also 'final'. Because it's 'final', it wouldn't have to go into the 
dynamic dispatch table. But because it's 'final', we have to make sure its 
implementati