Ejemplo n.º 1
0
 async def test_async_failure_in_main_task(self):
     after_await = False
     with pytest.raises(Fail):
         async with duet.new_scope() as scope:
             scope.spawn(mul, 2, 3)
             await duet.failed_future(Fail())
             after_await = True  # This should not run.
     assert not after_await
Ejemplo n.º 2
0
 async def test_sync_failure_in_main_task(self):
     # pylint: disable=unreachable
     after_await = False
     with pytest.raises(Fail):
         async with duet.new_scope() as scope:
             scope.spawn(mul, 2, 3)
             raise Fail()
             after_await = True  # This should not run.
     assert not after_await
Ejemplo n.º 3
0
 async def test_failure_in_spawned_task(self, fail_func):
     after_fail = False
     with pytest.raises(Fail):
         async with duet.new_scope() as scope:
             for a in range(10):
                 scope.spawn(mul, a, a)
             scope.spawn(fail_func)
             after_fail = True  # This should still run.
     assert after_fail
Ejemplo n.º 4
0
    async def test_run_all(self):
        results = {}

        async def func(a, b):
            results[a, b] = await mul(a, b)

        async with duet.new_scope() as scope:
            for a in range(10):
                for b in range(10):
                    scope.spawn(func, a, b)
        assert results == {(a, b): a * b for a in range(10) for b in range(10)}
Ejemplo n.º 5
0
    async def test_ordering(self):
        """Check that waiting coroutines acquire limiter in order."""
        limiter = duet.Limiter(1)
        acquired = []

        async def func(i):
            async with limiter:
                acquired.append(i)
                await duet.completed_future(None)

        async with duet.new_scope() as scope:
            for i in range(10):
                scope.spawn(func, i)

        assert acquired == sorted(acquired)
Ejemplo n.º 6
0
async def test_multiple_calls_to_future_set_result():
    """This checks a scenario that caused deadlocks in earlier versions."""
    async def set_results(*fs):
        for f in fs:
            await duet.completed_future(None)
            f.set_result(None)

    async with duet.new_scope() as scope:
        f0 = duet.AwaitableFuture()
        f1 = duet.AwaitableFuture()

        scope.spawn(set_results, f0)
        await f0

        # Calling f0.set_result again should not mark this main task as ready.
        # If it does, then the duet scheduler will try to advance the task and
        # will block on getting the result of f1. This prevents the background
        # `set_results` task from advancing and actually calling f1.set_result,
        # so we would deadlock.

        scope.spawn(set_results, f0, f1)
        await f1
Ejemplo n.º 7
0
 async def func():
     async with duet.new_scope() as scope:
         f = duet.AwaitableFuture()
         scope.spawn(lambda: f)
         f.set_exception(ValueError("oops!"))
         await duet.AwaitableFuture()
Ejemplo n.º 8
0
    async def collect_async(
        self,
        sampler: 'cirq.Sampler',
        *,
        concurrency: int = 2,
        max_total_samples: Optional[int] = None,
    ) -> None:
        """Asynchronously collects needed samples from a sampler.

        Examples:

            ```
            collector = cirq.PauliStringCollector(...)
            await sampler.collect_async(collector, concurrency=3)
            print(collector.estimated_energy())
            ```

        Args:
            sampler: The simulator or service to collect samples from.
            concurrency: Desired number of sampling jobs to have in flight at
                any given time.
            max_total_samples: Optional limit on the maximum number of samples
                to collect.

        Returns:
            The collector's result after all desired samples have been
            collected.
        """
        results: duet.AsyncCollector[Tuple[CircuitSampleJob, 'cirq.Result']] = duet.AsyncCollector()
        job_error = None
        running_jobs = 0
        queued_jobs: List[CircuitSampleJob] = []
        remaining_samples = np.infty if max_total_samples is None else max_total_samples

        async def run_job(job):
            nonlocal job_error
            try:
                result = await sampler.run_async(job.circuit, repetitions=job.repetitions)
            except Exception as error:
                if not job_error:
                    results.error(error)
                    job_error = error
            else:
                if not job_error:
                    results.add((job, result))

        # Keep dispatching and processing work.
        async with duet.new_scope() as scope:
            while True:
                # Fill up the work pool.
                while remaining_samples > 0 and running_jobs < concurrency:
                    if not queued_jobs:
                        queued_jobs.extend(_flatten_jobs(self.next_job()))

                    # If no jobs were given, stop asking until something completes.
                    if not queued_jobs:
                        break

                    # Start new sampling job.
                    new_job = queued_jobs.pop(0)
                    remaining_samples -= new_job.repetitions
                    running_jobs += 1
                    scope.spawn(run_job, new_job)

                # If no jobs are running, we're in a steady state. Halt.
                if not running_jobs:
                    break

                # Get result from next completed job and call on_job_result.
                job, result = await results.__anext__()
                running_jobs -= 1
                self.on_job_result(job, result)