<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 4336: bulk vs. task_scheduler</title>
<meta property="og:title" content="Issue 4336: bulk vs. task_scheduler">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue4336.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="4336"><a href="lwg-active.html#4336">4336</a>. <code>bulk</code> vs. <code>task_scheduler</code></h3>
<p><b>Section:</b> 33.13.5 <a href="https://wg21.link/exec.task.scheduler">[exec.task.scheduler]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Dietmar Kühl <b>Opened:</b> 2025-08-31 <b>Last modified:</b> 2025-09-01</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#exec.task.scheduler">active issues</a> in [exec.task.scheduler].</p>
<p><b>View all other</b> <a href="lwg-index.html#exec.task.scheduler">issues</a> in [exec.task.scheduler].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Normally, the scheduler type used by an operation can be deduced
when a sender is <code>connect</code>ed to a receiver from the
receiver's environment. The body of a coroutine cannot know about
the receiver the <code>task</code> sender gets <code>connect</code>ed
to. The implication is that the type of the scheduler used by the
coroutine needs to be known when the <code>task</code> is created.
To still allow custom schedulers used when connecting, the type-erased
scheduler <code>task_scheduler</code> is used. However, that leads
to surprises when algorithms are customised for a scheduler as is,
e.g., the case for <code>bulk</code> when used with a
<code>parallel_scheduler</code>: if <code>bulk</code> is
<code>co_awaited</code> within a coroutine using
<code>task_scheduler</code> it will use the default implementation
of <code>bulk</code> which sequentially executes the work, even if
the <code>task_scheduler</code> was initialised with a
<code>parallel_scheduler</code> (the exact invocation may actually
be slightly different or need to use <code>bulk_chunked</code> or
<code>bulk_unchunked</code> but that isn't the point being made):
</p>

<pre>
struct env {
    auto query(ex::get_scheduler_t) const noexcept { return ex::parallel_scheduler(); }
};
struct work {
    auto operator()(std::size_t s){ /*...*/ };
};

ex::sync_wait(
    ex::write_env(ex::bulk(ex::just(), 16u, work{}),
    env{}
));
ex::sync_wait(ex::write_env(
    []()->ex::task&lt;void, ex::env&lt;&gt;>&gt;{ co_await ex::bulk(ex::just(), 16u, work{}); }(),
    env{}
));
</pre>

<p>
The two invocations should probably both execute the work in parallel
but the coroutine version doesnt: it uses the <code>task_scheduler</code>
which doesnt have a specialised version of <code>bulk</code> to
potentially delegate in a type-erased form to the underlying
scheduler. It is straight forward to move the <code>write_env</code>
wrapper inside the coroutine which fixes the problem in this case
but this need introduces the potential for a subtle performance
bug. The problem is sadly not limited to a particular scheduler or
a particular algorithm: any scheduler/algorithm combination which
may get specialised can suffer from the specialised algorithm not
being picked up.
</p>

<p>
There are a few ways this problem can be addressed (this list of
options is almost certainly incomplete):
</p>

<ul>
<li>Accept the situation as is and advise users to be careful about
customised algorithms like bulk when using
<code>task_scheduler</code>.</li>
<li>Extend the interface of <code>task_scheduler</code> to deal
with a set of algorithms for which it provides a type-erased
interface. The interface would likely be more constrained and it
would use virtual dispatch at run-time. However, the set of covered
algorithms would necessarily be limited in some form.</li>
<li>To avoid the trap, make the use of known algorithms incompatible
with the use of <code>task_scheduler</code>, i.e., customise these
algorithms for <code>task_scheduler</code> such that a compile-time
error is produced.</li>
</ul>
<p>
A user who knows that the main purpose of a coroutine is to executed
an algorithm customised for a certain scheduler can use <code>task&lt;T,
E&gt;</code> with an environment <code>E</code> specifying exactly
that scheduler type.  However, this use may be nested within some
sender being <code>co_awaited</code> and users need to be aware
that the customisation wouldnt be picked up. Any approach I'm
currently aware of will have the problem that customised versions
of an algorithm are not used for algorithms we are currently unaware
of.
</p>


<p id="res-4336"><b>Proposed resolution:</b></p>
<p>
</p>





</body>
</html>
