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.7.1

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.7.1
File Size Uploaded
winloop-0.7.1.tar.gz 2.7 MB Details

Built distributions (wheels)

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

Total release size: 11.8 MB

Release files / winloop-0.7.1.tar.gz

Download URL winloop-0.7.1.tar.gz
Size 2.7 MB
Tags Source
SHA-256 checksum
How to use checksums
2ea92f36493477427ca3c7f4cb84a45f47f5feb3559dfe4b660d8e8068171a47
BLAKE2b-256 checksum
How to use checksums
2a660a8c65d4bb4504945aba3cc399588e06e1ea9a503cb6fd70f4b68c1f3b4d
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.7.1-cp314-cp314t-win_arm64.whl

Download URL winloop-0.7.1-cp314-cp314t-win_arm64.whl
Size 660.5 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows ARM64
SHA-256 checksum
How to use checksums
2c6c1306da9b998e167930f9b0f7f8e3e6c9c75f6a666277a53ad9fa3afa694c
BLAKE2b-256 checksum
How to use checksums
0452715f8ec02883145aa17f8a47f6bf878acc28db194ffcb3e99eb7bd270ff9
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.7.1-cp314-cp314t-win_amd64.whl

Download URL winloop-0.7.1-cp314-cp314t-win_amd64.whl
Size 760.2 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
d1d3cf643c6f652aa3be42168df90d086508853fc40c58b3d1b3397577ffa667
BLAKE2b-256 checksum
How to use checksums
bab0c3ec01a05d100bc47734815ee39020d5ee3678731125a02c2b46922b4e4e
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.7.1-cp314-cp314-win_arm64.whl

Download URL winloop-0.7.1-cp314-cp314-win_arm64.whl
Size 612.8 kB
Tags CPython 3.14 Windows ARM64
SHA-256 checksum
How to use checksums
db04854c148a1ead62cbf63394d320dbb4c14fe7d33738012deb3ad5ecf41eef
BLAKE2b-256 checksum
How to use checksums
d311e5dea8140388a27ac6c57787bbf1f758bfadff410fc2cb797db0a51a188b
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.7.1-cp314-cp314-win_amd64.whl

Download URL winloop-0.7.1-cp314-cp314-win_amd64.whl
Size 703.6 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
86a78413b3ae9c6d6c5f9cc0a16a0ab7c48040df7952321f095b8b9b72ec653d
BLAKE2b-256 checksum
How to use checksums
8971435fe9292708ae750057d10717026c71ff8f3f98b73fd7a2e4ccb5d3fa2d
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.7.1-cp313-cp313-win_arm64.whl

Download URL winloop-0.7.1-cp313-cp313-win_arm64.whl
Size 600.2 kB
Tags CPython 3.13 Windows ARM64
SHA-256 checksum
How to use checksums
20464fde92ecbcda14a590d4d88275abf19eca99ed3ae787e0dee1e054be51d5
BLAKE2b-256 checksum
How to use checksums
366af14211f8b7b907dfdb4da8e99cf1a99695405cc8c24793d9835f0d396189
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.7.1-cp313-cp313-win_amd64.whl

Download URL winloop-0.7.1-cp313-cp313-win_amd64.whl
Size 694.4 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
0aa944cb845ba5d6420fe53733feb3fb474600b298202ec2bd7cb03f46502331
BLAKE2b-256 checksum
How to use checksums
452d7c14e1ec68d14b731bfc6d0480fce2a2c88e3248465b594161a28a9ed2e9
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.7.1-cp312-cp312-win_arm64.whl

Download URL winloop-0.7.1-cp312-cp312-win_arm64.whl
Size 600.8 kB
Tags CPython 3.12 Windows ARM64
SHA-256 checksum
How to use checksums
6f2f90622542382bf9304b5ec9d252102f444bc3b445e24515250d7c62d62702
BLAKE2b-256 checksum
How to use checksums
1ff01f7c199da23ff8d9e8fcbafade3ad11dcb1005c58eac93991255c262fe06
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.7.1-cp312-cp312-win_amd64.whl

Download URL winloop-0.7.1-cp312-cp312-win_amd64.whl
Size 695.3 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
9bb416a2f0fee52dcdda3137358c56b48bfb63c443e11232d4c04353b56d39b0
BLAKE2b-256 checksum
How to use checksums
45a7e67a4e6156c159bd4ae3eaab1075914c32c2ee2b8fe0ff1894c2119a2a67
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.7.1-cp311-cp311-win_arm64.whl

Download URL winloop-0.7.1-cp311-cp311-win_arm64.whl
Size 602.4 kB
Tags CPython 3.11 Windows ARM64
SHA-256 checksum
How to use checksums
ae1808cfbc608e92577cef81131674d93efed548090995760fd1cd721aa50dbb
BLAKE2b-256 checksum
How to use checksums
2cd2abb25356ff35882dccdc5c558e2a78cef05b62e24d10edb397a7c3b4b445
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.7.1-cp311-cp311-win_amd64.whl

Download URL winloop-0.7.1-cp311-cp311-win_amd64.whl
Size 673.4 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
19154f8be70bc9ce9455a9ca26d8ecd48cc6cf432b7ccbf57238c84db29ba53a
BLAKE2b-256 checksum
How to use checksums
124769650d40470ea5014f971f0bbf1c249e783a6048b7bb6d04782f0d032c16
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.7.1-cp310-cp310-win_arm64.whl

Download URL winloop-0.7.1-cp310-cp310-win_arm64.whl
Size 599.8 kB
Tags CPython 3.10 Windows ARM64
SHA-256 checksum
How to use checksums
9089b64e6afd297716290671852bf6ec0b70bef2a336613765271fe85832a256
BLAKE2b-256 checksum
How to use checksums
4165a66f68c8123193247d53e4c3c70eb0ac2d05bb7dbe56959527e8a3fa0b6c
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.7.1-cp310-cp310-win_amd64.whl

Download URL winloop-0.7.1-cp310-cp310-win_amd64.whl
Size 665.0 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
c94f574049aa1b35e8c6babe805f9c5bc73e7d3752b6a7696f0403cec98108a4
BLAKE2b-256 checksum
How to use checksums
5fd8ff1d165dfce5da41c493fe893fdbabbe0bcb582735e0a21f3f06c7b0c5ef
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.7.1-cp39-cp39-win_arm64.whl

Download URL winloop-0.7.1-cp39-cp39-win_arm64.whl
Size 600.4 kB
Tags CPython 3.9 Windows ARM64
SHA-256 checksum
How to use checksums
64fad5fe179ae5a35f9316f96b358979d8deaca2171d81eca48d6f95d677745e
BLAKE2b-256 checksum
How to use checksums
3c30bef1c87d73632e8c0922be0ec6040f3b760e35e4b3afadd4380ddae4bb3b
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.7.1-cp39-cp39-win_amd64.whl

Download URL winloop-0.7.1-cp39-cp39-win_amd64.whl
Size 666.3 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
a34fd0d7b081fe975d70af6cf7ed2c448066d4fc460c5a3686e20382cd6efc0f
BLAKE2b-256 checksum
How to use checksums
975aa40dac5110a4e8f3e9b661e511086cd8bce40af63fc3c39708efb642ea43
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.8.0

15 release files

0.7.2

15 release files

This release

0.7.1 This release

15 release files

0.7.0

15 release files

0.6.4

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