Skip to main content
Code style: black

IDIM

Winloop

PyPI version PyPI - Downloads License: MIT License: Apache-2.0

An alternative library for uvloop compatibility with Windows because let's face it. Windows' Python asyncio standard library is garbage, especially when Windows Defender decides to eat half of your RAM. I never really liked the fact that I couldn't make anything run faster especially when you have fiber internet connections in place and you've done all the optimizations you could possibly think of. It always felt disappointing when libuv is available for Windows but Windows was never compatible with uvloop.

Since nobody was willing to step in after so many years of waiting, I went ahead and downloaded the source code for uvloop and started modifying the source code to be Windows compatible by carefully removing and changing parts that were not made for Windows. Many hours of research went into making this library.

The differences with uvloop is that forking has been fully disabled and some smaller API calls had to be changed, error handling has been carefully modified and subprocesses release the GIL instead of forking out...

There is a performance increase of about 5 times with Winloop compared to using the WindowsSelectorEventLoopPolicy and WindowsProactorEventLoopPolicy which have been known to trigger SSL problems in Python 3.9. Winloop is a very good replacement for solving those SSL problems as well. This library also has comparable performance to its brother uvloop.

How to install Winloop on your Windows Operating System

pip install winloop

You can also clone the repository and build the extension yourself by running the command below if you wish to use or build this library locally. Note that you will need Cython and The Visual C++ extensions to compile this library on your own.

python setup.py build_ext --inplace

Reporting issues

If you find any bugs with this library be sure to open up an issue in the issuetracker. Me and other contributors will be happy try to help you figure out and diagnose your problems.

Making pull requests

We encourage anyone to make pull-requests to Winloop, containing anything from spelling mistakes to vulnerability patches. Every little bit helps keep this library maintained and alive. Make sure that you are able to compile the library with the steps shown above. We plan to implement a nightly workflow to verify one's pull-request in the future.

try:
    import aiohttp
    import aiohttp.web
except ImportError:
    skip_tests = True
else:
    skip_tests = False

import asyncio
import unittest
import weakref
import winloop
import sys

class TestAioHTTP(unittest.TestCase):
    def __init__(self, methodName: str = "test_aiohttp_basic_1") -> None:
        super().__init__(methodName)


    def setUp(self):
        self.loop = asyncio.get_event_loop()

    def test_aiohttp_basic_1(self):
        PAYLOAD = '<h1>It Works!</h1>' * 10000

        async def on_request(request):
            return aiohttp.web.Response(text=PAYLOAD)

        asyncio.set_event_loop(self.loop)
        app = aiohttp.web.Application()
        app.router.add_get('/', on_request)

        runner = aiohttp.web.AppRunner(app)
        self.loop.run_until_complete(runner.setup())
        site = aiohttp.web.TCPSite(runner, '0.0.0.0', '10000')
        self.loop.run_until_complete(site.start())
        port = site._server.sockets[0].getsockname()[1]

        async def test():
            # Make sure we're using the correct event loop.
            self.assertIs(asyncio.get_event_loop(), self.loop)

            for addr in (('localhost', port),
                         ('127.0.0.1', port)):
                async with aiohttp.ClientSession() as client:
                    async with client.get('http://{}:{}'.format(*addr)) as r:
                        self.assertEqual(r.status, 200)
                        result = await r.text()
                        self.assertEqual(result, PAYLOAD)

        self.loop.run_until_complete(test())
        self.loop.run_until_complete(runner.cleanup())

    def test_aiohttp_graceful_shutdown(self):
        async def websocket_handler(request):
            ws = aiohttp.web.WebSocketResponse()
            await ws.prepare(request)
            request.app['websockets'].add(ws)
            try:
                async for msg in ws:
                    await ws.send_str(msg.data)
            finally:
                request.app['websockets'].discard(ws)
            return ws

        async def on_shutdown(app):
            for ws in set(app['websockets']):
                await ws.close(
                    code=aiohttp.WSCloseCode.GOING_AWAY,
                    message='Server shutdown')

        asyncio.set_event_loop(self.loop)
        app = aiohttp.web.Application()
        app.router.add_get('/', websocket_handler)
        app.on_shutdown.append(on_shutdown)
        app['websockets'] = weakref.WeakSet()

        runner = aiohttp.web.AppRunner(app)
        self.loop.run_until_complete(runner.setup())
        site = aiohttp.web.TCPSite(runner, '0.0.0.0', '10000')
        self.loop.run_until_complete(site.start())
        port = site._server.sockets[0].getsockname()[1]

        async def client():
            async with aiohttp.ClientSession() as client:
                async with client.ws_connect(
                        'http://127.0.0.1:{}'.format(port)) as ws:
                    await ws.send_str("hello")
                    async for msg in ws:
                        assert msg.data == "hello"

        client_task = asyncio.ensure_future(client())

        async def stop():
            await asyncio.sleep(0.1)
            try:
                await asyncio.wait_for(runner.cleanup(), timeout=0.1)
            except Exception as e:
                print(e)
            finally:
                try:
                    client_task.cancel()
                    await client_task
                except asyncio.CancelledError:
                    pass

        self.loop.run_until_complete(stop())



if __name__ == "__main__":
    # print("tesing without winloop")
    # asyncio.DefaultEventLoopPolicy = asyncio.WindowsSelectorEventLoopPolicy
    # asyncio.DefaultEventLoopPolicy = asyncio.WindowsProactorEventLoopPolicy
    unittest.main()
    # Looks like winloop might be 3x faster than the Proctor Event Loop , THAT's A HUGE IMPROVEMENT!
    print("testing again but with winloop enabled")
    winloop.install()
    unittest.main()

The benchmarks for the code above are as follows

Benchmarks

TCP Connections


Asyncio Event Loop Policy Time (in Seconds)
WinLoopPolicy 0.493s
WindowsProactorEventLoopPolicy 2.510s
WindowsSelectorEventLoopPolicy 2.723s

That's a massive increase and jump from just TCP alone! I'll be posting more benchmarks soon, as I modify more of the current test suites made by uvloop...

How to Use Winloop with Fastapi

This was a cool little script I put together just to make Fastapi that much faster to handle:

# TODO this code example is deprecated
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import winloop
import uvicorn
import asyncio
import datetime

app = FastAPI()

@app.on_event("startup")
def make_assertion():
    # Check to make sure that we bypassed the original eventloop Policy....
    assert isinstance(asyncio.get_event_loop_policy(), winloop.WinLoopPolicy)


@app.get("/test")
async def test_get_request():
    return HTMLResponse("<html><body><h1>FAST API WORKS WITH WINLOOP!</h1></body></html>")


# starllete will use asyncio.to_thread() so that this can remain asynchronous
@app.get("/date")
def test_dynamic_response():
    return str(datetime.datetime.now())


# Although tricky to pass and is not normal, it does in fact work...
if __name__ == "__main__":
    winloop.install()
    # Winloop's eventlooppolicy will be passed to uvicorn after this point...
    loop = asyncio.get_event_loop()
    config = uvicorn.Config(app=app,port=10000,loop=loop)
    server = uvicorn.Server(config)
    asyncio.run(server.serve())

How To Use Winloop When Uvloop is not available

# Here's A small Example of using winloop when uvloop is not available to us
import sys
import aiohttp
import asyncio

async def main():
    async with aiohttp.ClientSession("https://httpbin.org") as client:
        async with client.get("/ip") as resp:
            print(await resp.json())

if __name__ == "__main__":
    if sys.platform in ('win32', 'cygwin', 'cli'):
        from winloop import run
    else:
        # if we're on apple or linux do this instead
        from uvloop import run
    run(main())

TODO-List

  • In Winloop 0.2.0 or before 2026 I would like to start planning to migrate to pytest so that things could be formatted a little better. A Migration Python script might be needed or looked into.

  • Update Fastapi Example to a more recent version of fastapi

  • Help Wanted. We're looking for other maintainers to help us.

  • Nightly Builds And Test Suite Workflows for anyone wanting to use newer unreleased versions. (Done, it runs now)

  • Adding in the necessary hooks for pyinstaller to compile this fast library to executable code even though hooks have been known to inflate the size of the .exe files. This is because calling hidden-imports for all the __init__.py modules might annoy some developers. (Luckily I'm aware of this issue because I've been doing this myself...) Update, This is now pending and I hope that it passes

  • write a workflow for nightly builds if necessary for verification of pull requests.

  • Update benchmarks (They are old) can't believe I maintained this project for over a year now...

Videos

Contributing

I put my heart and soul into this library ever since it began and any help is appreciated and means a lot to me, I have other things I wish to explore so every little bit helps

How Can I contribute?

  • I make and branch and make edits and then I do a pull requests before I just step in and add something new. This way you have time to review my additions, changes or feature beforehand.
  • Forking The library.
  • Fixing or editing workflows.
  • Finding and editing spelling mistakes.

Metadata

Release files for winloop 0.6.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for winloop 0.6.4
File Size Uploaded
winloop-0.6.4.tar.gz 2.6 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for winloop 0.6.4
File
winloop-0.6.4-cp314-cp314t-win_arm64.whl CPython 3.14 CPython 3.14 free-threading Windows ARM64 Details
winloop-0.6.4-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
winloop-0.6.4-cp314-cp314-win_arm64.whl CPython 3.14 CPython 3.14 Windows ARM64 Details
winloop-0.6.4-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
winloop-0.6.4-cp313-cp313-win_arm64.whl CPython 3.13 CPython 3.13 Windows ARM64 Details
winloop-0.6.4-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
winloop-0.6.4-cp312-cp312-win_arm64.whl CPython 3.12 CPython 3.12 Windows ARM64 Details
winloop-0.6.4-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
winloop-0.6.4-cp311-cp311-win_arm64.whl CPython 3.11 CPython 3.11 Windows ARM64 Details
winloop-0.6.4-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
winloop-0.6.4-cp310-cp310-win_arm64.whl CPython 3.10 CPython 3.10 Windows ARM64 Details
winloop-0.6.4-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
winloop-0.6.4-cp39-cp39-win_arm64.whl CPython 3.9 CPython 3.9 Windows ARM64 Details
winloop-0.6.4-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details

Total release size: 11.1 MB

Release files / winloop-0.6.4.tar.gz

Download URL winloop-0.6.4.tar.gz
Size 2.6 MB
Tags Source
SHA-256 checksum
How to use checksums
20a5de55b5be63ed559d041a7b2256b67bd42f3cf3a118d8c7a71e5442c8e9e9
BLAKE2b-256 checksum
How to use checksums
dc6ad7411c23709ddc40c318598848f78c9ca11117c288b5afb45bf7f8a23b88
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp314-cp314t-win_arm64.whl

Download URL winloop-0.6.4-cp314-cp314t-win_arm64.whl
Size 596.2 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows ARM64
SHA-256 checksum
How to use checksums
d5d642e5635dc98653a52dbe85a1048068cdf797c9a42b4bf4b9f6a0f7226562
BLAKE2b-256 checksum
How to use checksums
f2c2bd50aa75a2d6d8e6f3ea79f5bb9ceb33bc0620173fcf3a968ba42ee9e2c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp314-cp314t-win_amd64.whl

Download URL winloop-0.6.4-cp314-cp314t-win_amd64.whl
Size 722.7 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
b8a3c95c8b07637ce3bcd50b69903f8933f6ab1ef0da9548f8f567dcdf0f763e
BLAKE2b-256 checksum
How to use checksums
0e77bf9277af365c5e2abc2754b55fb9fb95f30c445186c64b1ccd0b8c94e30a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp314-cp314-win_arm64.whl

Download URL winloop-0.6.4-cp314-cp314-win_arm64.whl
Size 563.8 kB
Tags CPython 3.14 Windows ARM64
SHA-256 checksum
How to use checksums
c16df8143a9f9d1d1f7c51bc947720999db58d4d5b936b86b7bc9258de528fe8
BLAKE2b-256 checksum
How to use checksums
764fc0cc4ec076fd9b4aa99bd36f2969ae95cf1abbf64d2abb0bcbd4cfe84b93
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp314-cp314-win_amd64.whl

Download URL winloop-0.6.4-cp314-cp314-win_amd64.whl
Size 669.1 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
13b391ee3897630cec2391075641096fb7e5d09c3a92d3008f110eeeea32eeaf
BLAKE2b-256 checksum
How to use checksums
525fea9b6cba5e0ab4bf83c5ada2eefd7c1f4705c2bfd27184163fd0b328a7b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp313-cp313-win_arm64.whl

Download URL winloop-0.6.4-cp313-cp313-win_arm64.whl
Size 546.2 kB
Tags CPython 3.13 Windows ARM64
SHA-256 checksum
How to use checksums
4520ab3d501d54176fa28b1b41527ecfe6773e5148ff8d719d0be9b3b3b1414b
BLAKE2b-256 checksum
How to use checksums
56af884614aeaa29d14d57a4fb37f5fd9fdcc1831248966f2af4a1c458dad68e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp313-cp313-win_amd64.whl

Download URL winloop-0.6.4-cp313-cp313-win_amd64.whl
Size 660.3 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
ef6f2dfe5bf662791c2f32086e57dd788aa22d614881a6a3653b916d668fa70f
BLAKE2b-256 checksum
How to use checksums
1dca1bfe1dad18b992bb039ebe5f8fcc39d4a3eeec69164f326bffac2ca1ff17
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp312-cp312-win_arm64.whl

Download URL winloop-0.6.4-cp312-cp312-win_arm64.whl
Size 546.9 kB
Tags CPython 3.12 Windows ARM64
SHA-256 checksum
How to use checksums
543469da05f16d39f458df16bf8ac9a7da302342ac962de1f0192508e2bd4256
BLAKE2b-256 checksum
How to use checksums
df69e656ce5745223179a320ebee195fcac1d015c9e5c6e6b2c9ba4f23732afc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp312-cp312-win_amd64.whl

Download URL winloop-0.6.4-cp312-cp312-win_amd64.whl
Size 661.0 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
4670143d095948af5a68440deb275c73b602bb4df14e575e9628562fb1149a52
BLAKE2b-256 checksum
How to use checksums
71fb0677ff5858657986f51c385fef6906d0fb2660d285887abb934b9776a71d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp311-cp311-win_arm64.whl

Download URL winloop-0.6.4-cp311-cp311-win_arm64.whl
Size 548.1 kB
Tags CPython 3.11 Windows ARM64
SHA-256 checksum
How to use checksums
95580d21d951815eea3401113cd1e30228cde5b227c4f0c9b7d8a6973e799f39
BLAKE2b-256 checksum
How to use checksums
158d758c77c72cae5cc46f0250665a40e0ca71a6fce33fc6ceb1e7bf18893890
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp311-cp311-win_amd64.whl

Download URL winloop-0.6.4-cp311-cp311-win_amd64.whl
Size 637.9 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
6871e87acb7211688b34df71647673ff67e58ca76887b39cfd1e04624b06ca54
BLAKE2b-256 checksum
How to use checksums
b5736a58f830cc28cb8b16cedca49f8db3bb3a46fbf02074e5ff47044d3dfd61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp310-cp310-win_arm64.whl

Download URL winloop-0.6.4-cp310-cp310-win_arm64.whl
Size 545.6 kB
Tags CPython 3.10 Windows ARM64
SHA-256 checksum
How to use checksums
2b4b717e65b0c9c45fb1fcb3ebb7d12191872084088c6ca19477a38b89d72506
BLAKE2b-256 checksum
How to use checksums
f4ca29a9afad70ab07293059b363aa024cc7067655c4ea899211d0fb99cb0d2d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp310-cp310-win_amd64.whl

Download URL winloop-0.6.4-cp310-cp310-win_amd64.whl
Size 629.6 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
5339f42586c9817e510a05c83f9fea8ff966a25ab499e73ef9d523cb9a3814de
BLAKE2b-256 checksum
How to use checksums
beb8d1cfd1beb4e6a369112a88b50833f77f1f6f1331ac2a31d454f47f2585bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp39-cp39-win_arm64.whl

Download URL winloop-0.6.4-cp39-cp39-win_arm64.whl
Size 545.8 kB
Tags CPython 3.9 Windows ARM64
SHA-256 checksum
How to use checksums
1d54beb8420893258605ba1e9c11087d3038ac20bce165c4db306fd50a14b5f2
BLAKE2b-256 checksum
How to use checksums
c0d3deba83daadf0eb8bded3778e2503ce6ed19c18aa19cd878bdeb7bdf6c5f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.6.4-cp39-cp39-win_amd64.whl

Download URL winloop-0.6.4-cp39-cp39-win_amd64.whl
Size 630.2 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
1cf8a5be289bf5f0536270c5eba7258804efe76442c8698433830c863a34e3e2
BLAKE2b-256 checksum
How to use checksums
1c1c11f4788ed217f035edb150ed1e7616ef64a3bae2d12e06cbd60fff0aad7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.7.0

15 release files

This release

0.6.4 This release

15 release files

0.6.3

16 release files

0.6.2

16 release files

0.6.0

22 release files

0.5.0

22 release files

0.4.2

22 release files

0.4.1

22 release files

0.3.1

22 release files

0.3.0

22 release files

0.2.2

22 release files

0.2.1

22 release files

0.2.0

16 release files

0.1.8

7 release files

0.1.7

7 release files

0.1.6

6 release files

0.1.5

6 release files

0.1.4

6 release files

0.1.3

5 release files

0.1.2

5 release files

0.1.1

5 release files

0.1.0

5 release files

0.0.9

5 release files

0.0.8

5 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

1 release file

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page