Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #67263 > unrolled thread
| Started by | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| First post | 2019-08-04 09:37 +0000 |
| Last post | 2019-08-05 07:46 +0000 |
| Articles | 20 on this page of 72 — 19 participants |
Back to article view | Back to comp.lang.c++
Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-04 09:37 +0000
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-04 02:58 -0700
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 09:18 -0400
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-04 11:15 -0700
Re: Why can't I understand what coroutines are? Louis Krupp <lkrupp@nospam.pssw.com.invalid> - 2019-08-04 04:58 -0600
Re: Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-05 08:31 +0000
Re: Why can't I understand what coroutines are? Martijn van Buul <pino@dohd.org> - 2019-08-05 09:51 +0000
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-05 14:44 -0700
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-04 14:08 +0100
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 09:23 -0400
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-04 14:36 +0100
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 10:31 -0400
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-04 16:42 +0100
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 16:43 -0400
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-04 13:58 -0700
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 17:36 -0400
Re: Why can't I understand what coroutines are? Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> - 2019-08-04 22:43 +0100
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-04 22:52 +0100
Re: Why can't I understand what coroutines are? Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> - 2019-08-04 23:10 +0100
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 21:32 -0400
Re: Why can't I understand what coroutines are? Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> - 2019-08-05 18:32 +0100
Re: Why can't I understand what coroutines are? scott@slp53.sl.home (Scott Lurndal) - 2019-08-05 17:48 +0000
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-05 20:14 -0400
Re: Why can't I understand what coroutines are? leigh.v.johnston@googlemail.com - 2019-08-06 04:13 -0700
Re: Why can't I understand what coroutines are? leigh.v.johnston@googlemail.com - 2019-08-06 04:23 -0700
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-06 22:19 +0100
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-06 15:19 -0700
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-07 00:01 +0100
Re: Why can't I understand what coroutines are? scott@slp53.sl.home (Scott Lurndal) - 2019-08-06 23:52 +0000
Re: Why can't I understand what coroutines are? Öö Tiib <ootiib@hot.ee> - 2019-08-06 16:57 -0700
Re: Why can't I understand what coroutines are? scott@slp53.sl.home (Scott Lurndal) - 2019-08-07 14:41 +0000
Re: Why can't I understand what coroutines are? Öö Tiib <ootiib@hot.ee> - 2019-08-08 07:10 -0700
Re: Why can't I understand what coroutines are? scott@slp53.sl.home (Scott Lurndal) - 2019-08-06 23:49 +0000
Re: Why can't I understand what coroutines are? Robert Wessel <robertwessel2@yahoo.com> - 2019-08-04 22:04 -0500
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-04 20:10 -0700
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-04 11:20 -0700
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-04 20:30 +0100
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-04 14:03 -0700
Re: Why can't I understand what coroutines are? Paavo Helde <myfirstname@osa.pri.ee> - 2019-08-05 09:36 +0300
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-05 14:34 -0700
Re: Why can't I understand what coroutines are? scott@slp53.sl.home (Scott Lurndal) - 2019-08-04 19:46 +0000
Re: Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-05 08:37 +0000
Re: Why can't I understand what coroutines are? David Brown <david.brown@hesbynett.no> - 2019-08-05 12:06 +0200
Re: Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-05 12:20 +0000
Re: Why can't I understand what coroutines are? David Brown <david.brown@hesbynett.no> - 2019-08-06 15:06 +0200
Re: Why can't I understand what coroutines are? David Brown <david.brown@hesbynett.no> - 2019-08-06 15:18 +0200
Re: Why can't I understand what coroutines are? Bonita Montero <Bonita.Montero@gmail.com> - 2019-08-06 13:58 +0200
Re: Why can't I understand what coroutines are? Sam <sam@email-scan.com> - 2019-08-04 09:17 -0400
Re: Why can't I understand what coroutines are? Robert Wessel <robertwessel2@yahoo.com> - 2019-08-04 10:12 -0500
Re: Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-05 08:42 +0000
Re: Why can't I understand what coroutines are? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-08-05 13:35 +0100
Re: Why can't I understand what coroutines are? Bart <bc@freeuk.com> - 2019-08-05 20:19 +0100
Re: Why can't I understand what coroutines are? Christian Gollwitzer <auriocus@gmx.de> - 2019-08-05 22:26 +0200
Re: Why can't I understand what coroutines are? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-05 23:09 +0200
Re: Why can't I understand what coroutines are? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-09 19:49 -0700
Re: Why can't I understand what coroutines are? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-10 05:13 +0200
Re: Why can't I understand what coroutines are? Christian Gollwitzer <auriocus@gmx.de> - 2019-08-10 08:23 +0200
Re: Why can't I understand what coroutines are? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-10 10:43 +0200
Re: Why can't I understand what coroutines are? Christian Gollwitzer <auriocus@gmx.de> - 2019-08-11 22:19 +0200
Re: Why can't I understand what coroutines are? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-14 08:25 -0700
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-10 00:19 -0700
Re: Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-11 21:16 +0000
Re: Why can't I understand what coroutines are? "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-05 23:43 -0700
Re: Why can't I understand what coroutines are? Bonita Montero <Bonita.Montero@gmail.com> - 2019-08-10 10:50 +0200
Re: Why can't I understand what coroutines are? Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> - 2019-08-04 17:57 +0100
Re: Why can't I understand what coroutines are? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-05 01:11 +0200
Re: Why can't I understand what coroutines are? Juha Nieminen <nospam@thanks.invalid> - 2019-08-05 08:50 +0000
Re: Why can't I understand what coroutines are? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-05 16:59 +0200
Re: Why can't I understand what coroutines are? Manfred <noname@add.invalid> - 2019-08-06 16:24 +0200
Re: Why can't I understand what coroutines are? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-07 00:52 +0200
Re: Why can't I understand what coroutines are? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-09 18:11 -0700
Re: Why can't I understand what coroutines are? Martijn van Buul <pino@dohd.org> - 2019-08-05 07:46 +0000
Page 1 of 4 [1] 2 3 4 Next page →
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2019-08-04 09:37 +0000 |
| Subject | Why can't I understand what coroutines are? |
| Message-ID | <qi6910$1eht$1@adenine.netfront.net> |
C++20 will introduce support for coroutines. To this day, for reasons
that are completely mysterious even to me, I have *absolutely no idea*
what they are. I just don't get it.
I go to the Wikipedia page "Coroutine"... and it tells me nothing.
"Coroutines are computer program components that generalize subroutines
for non-preemptive multitasking, by allowing execution to be suspended
and resumed. Coroutines are well-suited for implementing familiar program
components such as cooperative tasks, exceptions, event loops, iterators,
infinite lists and pipes."
This tells me nothing. I don't get it.
"By contrast, coroutines can exit by calling other coroutines, which may
later return to the point where they were invoked in the original
coroutine; from the coroutine's point of view, it is not exiting but
calling another coroutine."
Can exit by calling other coroutines... And then the execution later
resumes from that calling point. This is not "exiting" but "yielding",
whatever that's supposed to mean.
Sounds like a normal function call to me, but what do I know? I can't
understand what this is saying. It's like it's speaking in legible
English, yet it somehow is complete gibberish at the same time. I don't
get it.
It then gives a pseudocode example of coroutines... that look exactly
like a function calling another (which then just returns to the
original caller).
==========================================
var q := new queue
coroutine produce
loop
while q is not full
create some new items
add the items to q
yield to consume
coroutine consume
loop
while q is not empty
remove some items from q
use the items
yield to produce
==========================================
This looks to me exactly like
==========================================
var q := new queue
coroutine produce
loop
while q is not full
create some new items
add the items to q
call consume
coroutine consume
while q is not empty
remove some items from q
use the items
return
==========================================
But what do I know? I don't get it.
Ok, Wikipedia is just a generic article about coroutines. Maybe
https://en.cppreference.com/w/cpp/language/coroutines has a better
explanation. It's done from the perspective of C++ in particular,
after all.
"A coroutine is a function that can suspend execution to be resumed
later. Coroutines are stackless: they suspend execution by returning
to the caller. This allows for sequential code that executes
asynchronously (e.g. to handle non-blocking I/O without explicit
callbacks), and also supports algorithms on lazy-computed infinite
sequences and other uses."
A function that can suspend execution to be resumed later...
Yeah, I don't get it. Allows sequential code that executes
asynchronously... What? Supports algorithms on lazy-computed infinite
sequences... Ok, but what does this all mean? I don't get it.
The examples given are complete gibberish. I have *absolutely no
idea* what something like this is supposed to mean:
co_await async_write(socket, buffer(data, n));
co_await? What?
It seems that everybody else is awaiting (hah!) and praising coroutines
like the second coming of Christ. Yet I just can't understand what they
are, or how exactly they are used or useful. All web pages I can find
are legible English that still somehow manages to be completely meaningless
gibberish that tells me nothing.
[toc] | [next] | [standalone]
| From | "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> |
|---|---|
| Date | 2019-08-04 02:58 -0700 |
| Message-ID | <qi6a8a$1086$1@gioia.aioe.org> |
| In reply to | #67263 |
On 8/4/2019 2:37 AM, Juha Nieminen wrote: > C++20 will introduce support for coroutines. To this day, for reasons > that are completely mysterious even to me, I have *absolutely no idea* > what they are. I just don't get it. [...] They are like Fibers on Windows: https://docs.microsoft.com/en-us/windows/win32/procthread/fibers http://man7.org/linux/man-pages/man3/getcontext.3.html https://docs.microsoft.com/en-us/windows/win32/procthread/user-mode-scheduling
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2019-08-04 09:18 -0400 |
| Message-ID | <cone.1564924708.153661.25830.1004@monster.email-scan.com> |
| In reply to | #67264 |
[Multipart message — attachments visible in raw view] — view raw
Chris M. Thomasson writes: > On 8/4/2019 2:37 AM, Juha Nieminen wrote: >> C++20 will introduce support for coroutines. To this day, for reasons >> that are completely mysterious even to me, I have *absolutely no idea* >> what they are. I just don't get it. > [...] > > They are like Fibers on Windows: That's because Windows always sucked at multithreading.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> |
|---|---|
| Date | 2019-08-04 11:15 -0700 |
| Message-ID | <qi77ct$1174$2@gioia.aioe.org> |
| In reply to | #67269 |
On 8/4/2019 6:18 AM, Sam wrote: > Chris M. Thomasson writes: > >> On 8/4/2019 2:37 AM, Juha Nieminen wrote: >>> C++20 will introduce support for coroutines. To this day, for reasons >>> that are completely mysterious even to me, I have *absolutely no idea* >>> what they are. I just don't get it. >> [...] >> >> They are like Fibers on Windows: > > That's because Windows always sucked at multithreading. > > lol. ;^)
[toc] | [prev] | [next] | [standalone]
| From | Louis Krupp <lkrupp@nospam.pssw.com.invalid> |
|---|---|
| Date | 2019-08-04 04:58 -0600 |
| Message-ID | <bpcdkelmgr0fltsvlm9qdiq5ufsqgii0qa@4ax.com> |
| In reply to | #67263 |
On Sun, 4 Aug 2019 09:37:39 -0000 (UTC), Juha Nieminen
<nospam@thanks.invalid> wrote:
>C++20 will introduce support for coroutines. To this day, for reasons
>that are completely mysterious even to me, I have *absolutely no idea*
>what they are. I just don't get it.
<snip>
It might help to look at coroutines in another language, say Lua.
A main program and a coroutine cooperate like this:
The main program creates the coroutine object, associating it with a
function to be executed. At some point, the main program hands control
to the coroutine, possibly passing it arguments, and then waits for
the coroutine to either yield (or return) and possibly pass back
results. When the main program gets around to it, it resumes the
coroutine and waits again for it to yield or return.
The coroutine wakes up when it's told, possibly accepting arguments,
and then does whatever it wants until it decides it's time to either
yield control back to the main program or return, possibly passing
results back to the main program. A coroutine that yields waits until
it's told to resume by the main program; a coroutine that returns
simply goes away and cannot be told to resume.
Here's a simple example of a program that does a couple of trivial
computations and then quits:
===
-- Function to run in coroutine
--
function cf(n)
print("coroutine beginning n = ", n)
k = n * n
print("coroutine yielding, returning ", k)
coroutine.yield(k)
print("coroutine resuming")
k = k * n
print("coroutine yielding, returning", k)
coroutine.yield(k)
print("coroutine resuming")
k = -1
print("coroutine all done, returning", k)
return(k)
end
-- Main program
--
print("main creating coroutine")
co = coroutine.create(cf)
print("main telling coroutine to resume (actually, to start)")
print("main waiting for coroutine to yield or return")
status, result = coroutine.resume(co, 7)
print("main result from coroutine = ", result)
print("main telling coroutine to resume")
print("main waiting for coroutine to yield or return")
status, result = coroutine.resume(co)
print("main result from coroutine = ", result)
print("main telling coroutine to resume")
print("main waiting for coroutine to yield or return")
status, result = coroutine.resume(co)
print("main result from coroutine = ", result)
===
The output:
main creating coroutine
main telling coroutine to resume (actually, to start)
main waiting for coroutine to yield or return
coroutine beginning n = 7
coroutine yielding, returning 49
main result from coroutine = 49
main telling coroutine to resume
main waiting for coroutine to yield or return
coroutine resuming
coroutine yielding, returning 343
main result from coroutine = 343
main telling coroutine to resume
main waiting for coroutine to yield or return
coroutine resuming
coroutine all done, returning -1
main result from coroutine = -1
I hope this helps a little.
Louis
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2019-08-05 08:31 +0000 |
| Message-ID | <qi8pgi$4c5$1@adenine.netfront.net> |
| In reply to | #67265 |
Louis Krupp <lkrupp@nospam.pssw.com.invalid> wrote: > A main program and a coroutine cooperate like this: > > The main program creates the coroutine object, associating it with a > function to be executed. At some point, the main program hands control > to the coroutine, possibly passing it arguments, and then waits for > the coroutine to either yield (or return) and possibly pass back > results. When the main program gets around to it, it resumes the > coroutine and waits again for it to yield or return. > > The coroutine wakes up when it's told, possibly accepting arguments, > and then does whatever it wants until it decides it's time to either > yield control back to the main program or return, possibly passing > results back to the main program. A coroutine that yields waits until > it's told to resume by the main program; a coroutine that returns > simply goes away and cannot be told to resume. I'm still not sure how that's different from a regular function. Or, perhaps more precisely, a lambda function (because as far as I understand, a coroutine can have its own state, just like a lambda can have captured variables, making the lambda effectively a stateful functor.) Is the difference that a coroutine can "return" (so to speak) from anywhere inside itself, and the next time it gets "called" again it resumes from that point forward, rather than from the beginning (like a lambda would)? I'm still not exactly sure how that's so useful in practice (compared to stateful functors, like lambdas.)
[toc] | [prev] | [next] | [standalone]
| From | Martijn van Buul <pino@dohd.org> |
|---|---|
| Date | 2019-08-05 09:51 +0000 |
| Message-ID | <5d47fc05$0$2234$e4fe514c@news.kpn.nl> |
| In reply to | #67298 |
* Juha Nieminen:
> Is the difference that a coroutine can "return" (so to speak)
> from anywhere inside itself, and the next time it gets "called"
> again it resumes from that point forward, rather than from the
> beginning (like a lambda would)?
Yup. It acts like a blocking call, in a way.
> I'm still not exactly sure how that's so useful in practice
> (compared to stateful functors, like lambdas.)
Consider a producer/consumer implemented using threads. In this
case 'publish' and 'consume' operate on some kind of queue, possibly
with a depth of 1. If a producer publishes something to a full queue,
it blocks. If the consumer tries to consume from an empty queue, it
blocks.
class ProducerClass
{
[...]
void mainLoop()
{
while ( ... )
{
Item newItem;
[... do work on newItem ...]
publish( newItem);
}
}
}
class ConsumerClass
{
[...]
void mainLoop()
{
while ( ... )
{
std::vector<Item> packet;
packet.reserve(10);
for (int i = 0; i < packet.capacity(); ++i)
{
Item newItem = consume();
[.. possibly do something on newItem ...]
packet.push_back(newItem);
}
[... do something on a packet of 10 items ...]
}
}
}
In this case, having the consumer and producer execute in their own
thread offers no performance benefit, but it might still be very beneficial
to implement it this way, depending on details of either consumer or
producer. As with all examples, the above example is a bit silly.
In this case, with a 1:1 relationship between consumer and producer, such
a threaded solution would offer no parallelisation, so using threads here
only serves to simplify the implementation of the consumer or producer -
performancewise it's detrimental. In this case, coroutines would offer
a compromise: The separation and implementation benefits of a threaded
solution, without the overhead caused by blocking.
Another possible use of coroutines would be iterators. Suppose I have a
struct Foo
{
};
struct Bar
{
[...]
std::list<Foo> foos;
}
struct Quux
{
[...]
std::vector<Bar> bars;
}
struct Wibble
{
std::map< ..., Quux> quuxMap;
}
Suppose I want to offer a way to iterate over all instances of "Foo" inside
a "Wibble", without exposing any of the classes inbetween (because they're
private to an implementation, for example). There are numerous options:
* Create a std::container<Foo> GetFoos(const Wibble &) method. Could be
expensive (because Foo is expensive to copy), impossible (because
Foo has a deleted copy constructor) - and is generally undesireable
anyway.
* Create an
ApplyOnFoos(const Wibble &, const std::function<void(const Foo&)> &callback)
method (or something similar using templates, details schmetails) that
iterates over all elements and calls the callback function for every
instance of 'Foo'. Could work, but the receiving end might have
to capture quite a bit to make this work.
* Create an iterator class along the line of
class outputFunctor
{
outputFunctor(Wibble &) {...}
std::optional<std::reference_wrapper<Foo>> operator() {...}
}
(Or create an STL iterator, which is essentially the same). Will
definately work, but implementation is going to be awkward.
The first two have the benefit that their implementation can use simple
constructs (more to the point: A nested range-based for loop will do the
trick). Without coroutines, implementing the functor will require storing
iterators to the intermediate class inside the functor. With coroutines,
you can implement it using the same simple nested-range for loop.
I haven't touched C++'s coroutines yet (I'm waiting for C++20 to arrive)
so I don't know whether the required boilerplate will offset any
implementation benefits, but in Lua it would be something like
function outputIterator(wibble)
local _generator = coroutine.create(
function()
for (_, quux) in pairs(wibble.quuxMap) do
for (_, bar) in pairs(quux.bars) do
for(_, foo) in pairs(bar.foos) do
coroutine.yield(foo)
end
end
end
end)
return function ()
local _, nextFoo = coroutine.resume(_generator)
return nextFoo
end
end
usage:
local myWbble = [....]
for (foo in outputIterator(myWibble)) do
print ("Yay, a foo!", tostring(foo))
end
(Untested, and my lua is a bit rusty)
--
Martijn van Buul - pino@dohd.org
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> |
|---|---|
| Date | 2019-08-05 14:44 -0700 |
| Message-ID | <qia80k$a7q$1@gioia.aioe.org> |
| In reply to | #67302 |
On 8/5/2019 2:51 AM, Martijn van Buul wrote:
> * Juha Nieminen:
>
>> Is the difference that a coroutine can "return" (so to speak)
>> from anywhere inside itself, and the next time it gets "called"
>> again it resumes from that point forward, rather than from the
>> beginning (like a lambda would)?
>
> Yup. It acts like a blocking call, in a way.
>
>> I'm still not exactly sure how that's so useful in practice
>> (compared to stateful functors, like lambdas.)
>
> Consider a producer/consumer implemented using threads. In this
> case 'publish' and 'consume' operate on some kind of queue, possibly
> with a depth of 1. If a producer publishes something to a full queue,
> it blocks. If the consumer tries to consume from an empty queue, it
> blocks.
>
> class ProducerClass
> {
> [...]
>
> void mainLoop()
> {
> while ( ... )
> {
> Item newItem;
>
> [... do work on newItem ...]
>
> publish( newItem);
> }
> }
> }
>
> class ConsumerClass
> {
> [...]
>
> void mainLoop()
> {
> while ( ... )
> {
> std::vector<Item> packet;
> packet.reserve(10);
>
> for (int i = 0; i < packet.capacity(); ++i)
> {
> Item newItem = consume();
>
> [.. possibly do something on newItem ...]
> packet.push_back(newItem);
> }
>
> [... do something on a packet of 10 items ...]
>
> }
> }
> }
>
> In this case, having the consumer and producer execute in their own
> thread offers no performance benefit, but it might still be very beneficial
> to implement it this way, depending on details of either consumer or
> producer. As with all examples, the above example is a bit silly.
>
> In this case, with a 1:1 relationship between consumer and producer, such
> a threaded solution would offer no parallelisation, so using threads here
> only serves to simplify the implementation of the consumer or producer -
> performancewise it's detrimental. [...]
Actually, single producer, single consumer queues are pretty nice. The
consumer thread can work on things without bothering the procuder
thread, and vise versa. The sync can be implemented without using any
atomic RMW.
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-08-04 14:08 +0100 |
| Message-ID | <20190804140857.f1a22df42a76938b234edf4b@cvine--nospam--.freeserve.co.uk> |
| In reply to | #67263 |
On Sun, 4 Aug 2019 09:37:39 -0000 (UTC) Juha Nieminen <nospam@thanks.invalid> wrote: [snip] > A function that can suspend execution to be resumed later... > Yeah, I don't get it. Allows sequential code that executes > asynchronously... What? Supports algorithms on lazy-computed infinite > sequences... Ok, but what does this all mean? I don't get it. > > The examples given are complete gibberish. I have *absolutely no > idea* what something like this is supposed to mean: > > co_await async_write(socket, buffer(data, n)); > > co_await? What? > > It seems that everybody else is awaiting (hah!) and praising coroutines > like the second coming of Christ. Yet I just can't understand what they > are, or how exactly they are used or useful. All web pages I can find > are legible English that still somehow manages to be completely meaningless > gibberish that tells me nothing. You have summarized coroutines quite well in your posting, and I shouldn't get too hung up on one particular implementation (the one which may be included in C++20). The easiest coroutines to understand, and the ones used to implement "await" semantics on asynchronous operations, are asymmetrical coroutines implemented using delimited continuations. These normally have only two control-flow operations, namely a "yield" or "suspend" operation, and a "resume" operation. When a function executes a "yield" or "suspend" operation, it returns control to its caller, somewhat like a return statement. However, unlike a return statement, a "resume" operation on the coroutine in question will return program execution to the point at which the yield previously occurred. Asynchronous programming with callbacks normally works so that when a i/o operation might block because the resource in question (read or write) is unavailable, instead of blocking the function returns immediately and registers a callback with the program's event loop (usually based on select() or poll()), representing the i/o operation's continuation when the resource becomes available. Programming this way using callbacks in the style of, say, Node.js is troublesome because it gives rise to what is sometimes called inversion of control, aka "callback hell". In particular, control flow ceases to appear as a sequential series of i/o operations which can easily be reasoned about. Coroutines can offer a way out because when an i/o resource is unavailable the i/o operation concerned can (i) register a callback with the event loop which resumes the operation when the resource becomes available, and then (ii) suspends to the caller (which indirectly is the event loop). When the resource becomes available the event loop resumes the coroutine at the point of suspension, so "tricking" the control flow so that it appears to the coder to be sequential (like blocking i/o) even though it is in fact executing asynchronously via an event loop. The scheme language has first-class continuations built into the language which makes implementing coroutines relatively trivial. Here is one library which uses asymmetrical coroutines for the purposes mentioned above which may or may not help: https://github.com/ChrisVine/chez-a-sync/wiki . ECMAscript and python also now have somewhat more limited asymmetrical coroutines.
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2019-08-04 09:23 -0400 |
| Message-ID | <cone.1564925032.455203.25830.1004@monster.email-scan.com> |
| In reply to | #67267 |
[Multipart message — attachments visible in raw view] — view raw
Chris Vine writes: > Asynchronous programming with callbacks normally works so that when a > i/o operation might block because the resource in question (read or > write) is unavailable, instead of blocking the function returns > immediately and registers a callback with the program's event loop > (usually based on select() or poll()), representing the i/o operation's > continuation when the resource becomes available. Programming this way > using callbacks in the style of, say, Node.js is troublesome because it > gives rise to what is sometimes called inversion of control, aka > "callback hell". In particular, control flow ceases to appear as a > sequential series of i/o operations which can easily be reasoned about. This problem was solved a long time ago. It is called "threads". The funniest thing about this is that Gnome is most extreme case of this. The entire Gnome stack is just one event dispatching main loop. Everything is callbacks. But since Gnome is C code, none of this will help it, that's the funny part.
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-08-04 14:36 +0100 |
| Message-ID | <20190804143647.511134ccbc3ef6771a692cf7@cvine--nospam--.freeserve.co.uk> |
| In reply to | #67270 |
On Sun, 04 Aug 2019 09:23:52 -0400 Sam <sam@email-scan.com> wrote: > Chris Vine writes: > > > Asynchronous programming with callbacks normally works so that when a > > i/o operation might block because the resource in question (read or > > write) is unavailable, instead of blocking the function returns > > immediately and registers a callback with the program's event loop > > (usually based on select() or poll()), representing the i/o operation's > > continuation when the resource becomes available. Programming this way > > using callbacks in the style of, say, Node.js is troublesome because it > > gives rise to what is sometimes called inversion of control, aka > > "callback hell". In particular, control flow ceases to appear as a > > sequential series of i/o operations which can easily be reasoned about. > > This problem was solved a long time ago. It is called "threads". > > The funniest thing about this is that Gnome is most extreme case of this. > The entire Gnome stack is just one event dispatching main loop. Everything > is callbacks. But since Gnome is C code, none of this will help it, that's > the funny part. Threads are very definitely not the answer. Threads work well with cpu-bound workloads. They are hopeless with i/o-bound workloads, which is why co-operative (possibly single-threaded) multi-tasking using coroutines has become popular. If you use native OS threads for i/o bound workloads, you are doing it wrong.
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2019-08-04 10:31 -0400 |
| Message-ID | <cone.1564929062.699026.27147.1004@monster.email-scan.com> |
| In reply to | #67271 |
[Multipart message — attachments visible in raw view] — view raw
Chris Vine writes: > On Sun, 04 Aug 2019 09:23:52 -0400 > Sam <sam@email-scan.com> wrote: > > > > The funniest thing about this is that Gnome is most extreme case of this. > > The entire Gnome stack is just one event dispatching main loop. Everything > > is callbacks. But since Gnome is C code, none of this will help it, that's > > the funny part. > > Threads are very definitely not the answer. Threads work well with > cpu-bound workloads. They are hopeless with i/o-bound workloads, which > is why co-operative (possibly single-threaded) multi-tasking using > coroutines has become popular. So instead of simply spawning off a separate thread whose only job is a laughably simple loop that wait for I/O to happen, and that do something simple with it, like saving some data that's read from the socket into a file, it's much easier to build another rube-goldbergian event-loop based contraption, and the entire application now must be dragged, kicking and screaming, into rebuilding under that framework? That's the easier approach? Coroutines are not going to be better at this, either. > If you use native OS threads for i/o bound workloads, you are doing it > wrong. Nope. One only needs to understand that I/O bound workloads is not the only reason that threads exist.
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-08-04 16:42 +0100 |
| Message-ID | <20190804164254.8072d620ed92d63e3d8c9d42@cvine--nospam--.freeserve.co.uk> |
| In reply to | #67272 |
On Sun, 04 Aug 2019 10:31:02 -0400 Sam <sam@email-scan.com> wrote: > Chris Vine writes: > > > On Sun, 04 Aug 2019 09:23:52 -0400 > > Sam <sam@email-scan.com> wrote: > > > > > > The funniest thing about this is that Gnome is most extreme case of this. > > > The entire Gnome stack is just one event dispatching main loop. Everything > > > is callbacks. But since Gnome is C code, none of this will help it, that's > > > the funny part. > > > > Threads are very definitely not the answer. Threads work well with > > cpu-bound workloads. They are hopeless with i/o-bound workloads, which > > is why co-operative (possibly single-threaded) multi-tasking using > > coroutines has become popular. > > So instead of simply spawning off a separate thread whose only job is a > laughably simple loop that wait for I/O to happen, and that do something > simple with it, like saving some data that's read from the socket into a > file, it's much easier to build another rube-goldbergian event-loop based > contraption, and the entire application now must be dragged, kicking and > screaming, into rebuilding under that framework? That's the easier approach? You have it wrong. For toy programs or for cases where there are only a few concurrent i/o operations running at any one time then native threads are fine. But using native OS threads with blocking i/o on i/o-bound workloads does not scale. No one writes a server these days with one thread per connection, which would be required for your blocking i/o: instead you multiplex connections with poll/epoll/kqueue and tune the number of threads to the workload and the number of cores available. You can have millions of C++20-style stackless coroutines running at any one time on a thread, although you are going to run out of file descriptors before any such limit is reached (I see that my relatively modest 8 core machine has a hard maximum of 805038 open descriptors although other things would probably break before then). > Coroutines are not going to be better at this, either. > > > If you use native OS threads for i/o bound workloads, you are doing it > > wrong. > > Nope. One only needs to understand that I/O bound workloads is not the only > reason that threads exist. Clueless.
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2019-08-04 16:43 -0400 |
| Message-ID | <cone.1564951432.763732.27147.1004@monster.email-scan.com> |
| In reply to | #67274 |
[Multipart message — attachments visible in raw view] — view raw
Chris Vine writes: > > You have it wrong. > > For toy programs or for cases where there are only a few concurrent i/o > operations running at any one time then native threads are fine. But > using native OS threads with blocking i/o on i/o-bound workloads does > not scale. Says who? > No one writes a server these days with one thread per > connection, which would be required for your blocking i/o: instead you > multiplex connections with poll/epoll/kqueue and tune the number of > threads to the workload and the number of cores available. Maybe you just don't know many people who write server code. > You can have > millions of C++20-style stackless coroutines running at any one time > on a thread, although you are going to run out of file descriptors > before any such limit is reached Sure, and since coroutines introduce an additional level of complexity – something also needs to be aware and keep track of which coroutine has something that needs to be done, instead of efficiently encapsulating all I/O handling logic in a simple, straightforward, execution thread; and no other part of the code needs to give a shit – it still unclear what problem they're trying to solve. Modern operating systems have no problems scaling to thousands, and maybe even tens of thousands of execution threads. Perhaps you don't have much exposure to them, and are only exposed to technically flawed operating system, with utterly crappy thread implementations? > > > If you use native OS threads for i/o bound workloads, you are doing it > > > wrong. > > > > Nope. One only needs to understand that I/O bound workloads is not the only > > reason that threads exist. > > Clueless. As opposed to someone who religiously believes that the only reason one someone would use threads is in CPU-bound code? Maybe you should talk to Chrome and Firefox folks, and teach them how to write code, since you know so much about it, and explain how stupid they are, creating dozens of threads even when most of their load is I/O bound.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> |
|---|---|
| Date | 2019-08-04 13:58 -0700 |
| Message-ID | <qi7gt6$ct1$1@gioia.aioe.org> |
| In reply to | #67282 |
On 8/4/2019 1:43 PM, Sam wrote: > Chris Vine writes: > >> >> You have it wrong. >> >> For toy programs or for cases where there are only a few concurrent i/o >> operations running at any one time then native threads are fine. But >> using native OS threads with blocking i/o on i/o-bound workloads does >> not scale. > > Says who? > >> No one writes a server these days with one thread per >> connection, which would be required for your blocking i/o: instead you >> multiplex connections with poll/epoll/kqueue and tune the number of >> threads to the workload and the number of cores available. > > Maybe you just don't know many people who write server code. I remember using IOCP back on WinNT 4. The idea of a thread per connection simply does not scale. However, creating a thread or two per CPU, and using a queue, like IOCP can scale. > >> You can have >> millions of C++20-style stackless coroutines running at any one time >> on a thread, although you are going to run out of file descriptors >> before any such limit is reached > > Sure, and since coroutines introduce an additional level of complexity – > something also needs to be aware and keep track of which coroutine has > something that needs to be done, instead of efficiently encapsulating > all I/O handling logic in a simple, straightforward, execution thread; > and no other part of the code needs to give a shit – it still unclear > what problem they're trying to solve. > > Modern operating systems have no problems scaling to thousands, and > maybe even tens of thousands of execution threads. Perhaps you don't > have much exposure to them, and are only exposed to technically flawed > operating system, with utterly crappy thread implementations? > >> > > If you use native OS threads for i/o bound workloads, you are >> doing it >> > > wrong. >> > >> > Nope. One only needs to understand that I/O bound workloads is not >> the only >> > reason that threads exist. >> >> Clueless. > > As opposed to someone who religiously believes that the only reason one > someone would use threads is in CPU-bound code? > > Maybe you should talk to Chrome and Firefox folks, and teach them how to > write code, since you know so much about it, and explain how stupid they > are, creating dozens of threads even when most of their load is I/O bound. >
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2019-08-04 17:36 -0400 |
| Message-ID | <cone.1564954572.633096.27147.1004@monster.email-scan.com> |
| In reply to | #67283 |
[Multipart message — attachments visible in raw view] — view raw
Chris M. Thomasson writes: > On 8/4/2019 1:43 PM, Sam wrote: >>> multiplex connections with poll/epoll/kqueue and tune the number of >>> threads to the workload and the number of cores available. >> >> Maybe you just don't know many people who write server code. > > I remember using IOCP back on WinNT 4. The idea of a thread per connection > simply does not scale. However, creating a thread or two per CPU, and using > a queue, like IOCP can scale. I agree that "a thread per connection simply does not scale" on Microsoft Windows. However that's only true for Microsoft Windows, and its crap multithreading. A thread per connection scales perfectly fine, on Linux. Even with hundreds of connections. Thread overhead is quite negligible on Linux, and you end up writing clean, orderly code that runs logically from start to finish, instead of getting torn into shreds in order to conform to event loop or callback-based design patterns.
[toc] | [prev] | [next] | [standalone]
| From | Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> |
|---|---|
| Date | 2019-08-04 22:43 +0100 |
| Message-ID | <jkI1F.72700$Bd4.70055@fx26.fr7> |
| In reply to | #67286 |
On 04/08/2019 22:36, Sam wrote: > Chris M. Thomasson writes: > >> On 8/4/2019 1:43 PM, Sam wrote: >>>> multiplex connections with poll/epoll/kqueue and tune the number of >>>> threads to the workload and the number of cores available. >>> >>> Maybe you just don't know many people who write server code. >> >> I remember using IOCP back on WinNT 4. The idea of a thread per >> connection simply does not scale. However, creating a thread or two per >> CPU, and using a queue, like IOCP can scale. > > I agree that "a thread per connection simply does not scale" on Microsoft > Windows. However that's only true for Microsoft Windows, and its crap > multithreading. > > A thread per connection scales perfectly fine, on Linux. Even with > hundreds of connections. Thread overhead is quite negligible on Linux, and > you end up writing clean, orderly code that runs logically from start to > finish, instead of getting torn into shreds in order to conform to event > loop or callback-based design patterns. Nonsense. You should have no more than one logical thread per physical thread for particular task type. /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin “You won’t burn in hell. But be nice anyway.” – Ricky Gervais “I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-08-04 22:52 +0100 |
| Message-ID | <20190804225258.6421be3b8cacabe051da4015@cvine--nospam--.freeserve.co.uk> |
| In reply to | #67286 |
On Sun, 04 Aug 2019 17:36:12 -0400 Sam <sam@email-scan.com> wrote: > Chris M. Thomasson writes: > > > On 8/4/2019 1:43 PM, Sam wrote: > >>> multiplex connections with poll/epoll/kqueue and tune the number of > >>> threads to the workload and the number of cores available. > >> > >> Maybe you just don't know many people who write server code. > > > > I remember using IOCP back on WinNT 4. The idea of a thread per connection > > simply does not scale. However, creating a thread or two per CPU, and using > > a queue, like IOCP can scale. > > I agree that "a thread per connection simply does not scale" on Microsoft > Windows. However that's only true for Microsoft Windows, and its crap > multithreading. > > A thread per connection scales perfectly fine, on Linux. Even with hundreds > of connections. Thread overhead is quite negligible on Linux, and you end up > writing clean, orderly code that runs logically from start to finish, > instead of getting torn into shreds in order to conform to event loop or > callback-based design patterns. I disagree. And "hundreds of connections" is not good enough.
[toc] | [prev] | [next] | [standalone]
| From | Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> |
|---|---|
| Date | 2019-08-04 23:10 +0100 |
| Message-ID | <6JI1F.54517$U17.3799@fx28.fr7> |
| In reply to | #67289 |
On 04/08/2019 22:52, Chris Vine wrote: > On Sun, 04 Aug 2019 17:36:12 -0400 > Sam <sam@email-scan.com> wrote: >> Chris M. Thomasson writes: >> >>> On 8/4/2019 1:43 PM, Sam wrote: >>>>> multiplex connections with poll/epoll/kqueue and tune the number of >>>>> threads to the workload and the number of cores available. >>>> >>>> Maybe you just don't know many people who write server code. >>> >>> I remember using IOCP back on WinNT 4. The idea of a thread per connection >>> simply does not scale. However, creating a thread or two per CPU, and using >>> a queue, like IOCP can scale. >> >> I agree that "a thread per connection simply does not scale" on Microsoft >> Windows. However that's only true for Microsoft Windows, and its crap >> multithreading. >> >> A thread per connection scales perfectly fine, on Linux. Even with hundreds >> of connections. Thread overhead is quite negligible on Linux, and you end up >> writing clean, orderly code that runs logically from start to finish, >> instead of getting torn into shreds in order to conform to event loop or >> callback-based design patterns. > > I disagree. And "hundreds of connections" is not good enough. You are correct to disagree. Sam has obviously never heard of "epoll". /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin “You won’t burn in hell. But be nice anyway.” – Ricky Gervais “I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."
[toc] | [prev] | [next] | [standalone]
| From | Sam <sam@email-scan.com> |
|---|---|
| Date | 2019-08-04 21:32 -0400 |
| Message-ID | <cone.1564968742.615770.1074.1004@monster.email-scan.com> |
| In reply to | #67289 |
[Multipart message — attachments visible in raw view] — view raw
Chris Vine writes: > On Sun, 04 Aug 2019 17:36:12 -0400 > Sam <sam@email-scan.com> wrote: > > > I agree that "a thread per connection simply does not scale" on Microsoft > > Windows. However that's only true for Microsoft Windows, and its crap > > multithreading. > > > > A thread per connection scales perfectly fine, on Linux. Even with hundreds > > of connections. Thread overhead is quite negligible on Linux, and you end > up > > writing clean, orderly code that runs logically from start to finish, > > instead of getting torn into shreds in order to conform to event loop or > > callback-based design patterns. > > I disagree. And "hundreds of connections" is not good enough. You can disagree all you want. Historical facts prove otherwise. Since ancient days, the simplest task on Unixes were done as pipelined tasks, as multiple execution contexts. $ sort <file | uniq -c That dates back decades.From the earlier days, shells were explicitly designed to execute pipelined commands. Pipelined commands were their main feature. All of this is pretty much I/O bound. Multiple execution threads. Because of that, and battle-tested over decades, Unix was tuned to effortlessly implement tasks that use multiple processes working in parallel. Threads were just the next evolution, dropping most of what little was left, in terms of per-execution context overhead. Linux inherited Unix's legacy, and orientation, towards low-overhead multiple execution threads. All the historical network server processes on Unix, then Linux, were multi- processor based. Even though select() existed pretty much since 4.2 BSD days, it was virtually unheard of for a network server to be a monolithic process, multiplexing for its clients using select(). An incoming network connection starts a new process, just for that network connection. Didn't matter what network service it was. SMTP, finger, login, or what, it was all one process per connection. There was a reason for that. It didn't take an Einstein to figure out that with a monolithic server, once it picked up an I/O event it had to do what that event needs to do, and nothing else can happen until that's done. Even if another client blurted out a packet, too bad, so sad. It needs to wait until the current I/O event's processing is done. It made a lot more sense to simply have another available CPU, not being busy with anything, run with it. And, goshdarndammit, if that socket had a different execution thread sucking from it, why, that spare CPU will know exactly what to do. So, monolithic processes were rare. They are a little bit more common today than before, but they are still a rarity. And, today, even network servers that kick off multiple processes per client can be found. So, sorry, but facts disagree: multiple execution contexts, either as standalone processes or lightweight intra-process threads rule the roost in I/O bound contexts. Linux inherits Unix's legacy in this respect, and the differences between processes and threads, on Linux, are mostly cosmetic. clone() creates both of them. You just specify which part of the parent process (virtual memory map, file descriptors, filesystem namespace etc…) are shared with the new execution context, and that's pretty much. I can understand why coming from a MS-Windows background makes someone frown at execution threads, unless all they do is stay away from the operating system, and work entirely on their own, spinning the CPU. The only reason stuff like IOCP exists on Windows is because windows sucks at multi- threading and multi-processing. It always sucked, and will likely always suck. But that's not the case with the real world out there. Being able to have a clean, encapsulated, logical execution thread, always busy with the forward march of progress from the start pointing to the finish line, without being forced into contorting into an event/dispatch based framework, results in smaller, leaner code without all that event-based/dispatching cruft. It doesn't matter which one of the file descriptors is now ready for I/O. It no longer matters. The OS kernel already figured it out, and there's no good reason for userspace to piss away more CPU cycles doing exactly the same thing. The OS kernel knows which I/O is done, and which thread is waiting on it, and it already knows whose ass to kick into gear. A such, execution threads are perfect for I/O-based load. It is no wonder that Linux rules the roost in TOP500 space. It's a dirty little secret that all those supercomputers are just a bunch of machines with optimized networking tying hundreds of thousands threads together. Yes, threads. Gee whiz, how can that possibly happen?
[toc] | [prev] | [next] | [standalone]
Page 1 of 4 [1] 2 3 4 Next page →
Back to top | Article view | comp.lang.c++
csiph-web