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

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

Built distributions (wheels)

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

Total release size: 11.9 MB

Release files / winloop-0.7.2.tar.gz

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

Download URL winloop-0.7.2-cp314-cp314t-win_arm64.whl
Size 661.5 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows ARM64
SHA-256 checksum
How to use checksums
ea6eea1d8d1785c9798a826e7ea81a042abc24fbe49ed01c286d3ed4b17df446
BLAKE2b-256 checksum
How to use checksums
9388f563799e2879782140ffb44d328e103aeca49c926d9a15963b1f42e25a09
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.2-cp314-cp314t-win_amd64.whl

Download URL winloop-0.7.2-cp314-cp314t-win_amd64.whl
Size 761.1 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
1fb17e09b1bb07a73d9d61da74585be8f536db0633a5e2cbc3584fa0bc3ff974
BLAKE2b-256 checksum
How to use checksums
3327f498c9aff90b5f49c9f279336af6d9d94108333504f237cab4a58a3a91f4
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.2-cp314-cp314-win_arm64.whl

Download URL winloop-0.7.2-cp314-cp314-win_arm64.whl
Size 613.7 kB
Tags CPython 3.14 Windows ARM64
SHA-256 checksum
How to use checksums
9ae25a7bae66c2b52535e9d9a781d55772f19796d7a89f0b4901f670473f5b65
BLAKE2b-256 checksum
How to use checksums
59977176b9174c333c4591c2a0031dd3b207180a92ca791b39c0d58e1ee5ca78
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.2-cp314-cp314-win_amd64.whl

Download URL winloop-0.7.2-cp314-cp314-win_amd64.whl
Size 704.5 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
1006d66b08563451f5b3bcd5e701997aada33df2cb6932657d1f2c566ff572fd
BLAKE2b-256 checksum
How to use checksums
68f63e515df2de24a0ea95d79820d53574a6da19abddc2d7a67c5f8b2bc4e830
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.2-cp313-cp313-win_arm64.whl

Download URL winloop-0.7.2-cp313-cp313-win_arm64.whl
Size 601.1 kB
Tags CPython 3.13 Windows ARM64
SHA-256 checksum
How to use checksums
29f013f95658e45ab8042a366bc3b1c12960d9352a7abd824ebccac4ef54bf56
BLAKE2b-256 checksum
How to use checksums
2245905f9ac877f2db2bb59030015b4d5dfa46aa82e037d66877476dee788032
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.2-cp313-cp313-win_amd64.whl

Download URL winloop-0.7.2-cp313-cp313-win_amd64.whl
Size 695.4 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
92c756b2bc21ad778fea20ab2395381bc4fc477a2795955f4501800491d808de
BLAKE2b-256 checksum
How to use checksums
d30406aed2b7bc1142559481ea510bd3d1b80e9b903476c4bae9452c1788b665
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.2-cp312-cp312-win_arm64.whl

Download URL winloop-0.7.2-cp312-cp312-win_arm64.whl
Size 601.7 kB
Tags CPython 3.12 Windows ARM64
SHA-256 checksum
How to use checksums
1fd1a6c08c7f756f526d5c4d6d6f96fb45129a800e2ae1a83be35d6623d9aaa5
BLAKE2b-256 checksum
How to use checksums
c104e278d1aa407364e32f8294bccc2b0823789fe6a45880b28770e5c5fc8cbb
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.2-cp312-cp312-win_amd64.whl

Download URL winloop-0.7.2-cp312-cp312-win_amd64.whl
Size 696.2 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
a303f9ca7ca602ba64570c6e6fb9aea46e5af14b0df3e262ce68b977730e7079
BLAKE2b-256 checksum
How to use checksums
853d6f798e05905c842b4ac7f648296ce628f535fda994a9ed1a5f4b95dfc3ce
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.2-cp311-cp311-win_arm64.whl

Download URL winloop-0.7.2-cp311-cp311-win_arm64.whl
Size 603.3 kB
Tags CPython 3.11 Windows ARM64
SHA-256 checksum
How to use checksums
95f8dbc4841b2192911b1c76bf798241ce01f8544258448d093ea2557bd41da9
BLAKE2b-256 checksum
How to use checksums
d8c806bae0b44278e88cbe286ee29769ee5b7c8bf9fdc3984a13f9860bad5a59
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.2-cp311-cp311-win_amd64.whl

Download URL winloop-0.7.2-cp311-cp311-win_amd64.whl
Size 674.3 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
0d254ab0b21428c84d8723d31da77512257e53462737439f53b4db0d3c70de40
BLAKE2b-256 checksum
How to use checksums
008194afce637d309ce6f3c74ab4fdc39288a138b2505bb4c3ca1916a37ef955
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.2-cp310-cp310-win_arm64.whl

Download URL winloop-0.7.2-cp310-cp310-win_arm64.whl
Size 600.7 kB
Tags CPython 3.10 Windows ARM64
SHA-256 checksum
How to use checksums
21bf2132dd34cfeb9670b09c7dfdaa6f4bf144a41ede65b7ecdedafbbe01f965
BLAKE2b-256 checksum
How to use checksums
08b57bfead764c0c39d7c7fabac1ea4fd87c292b1d44f5f6b3bbcc4721442a87
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.2-cp310-cp310-win_amd64.whl

Download URL winloop-0.7.2-cp310-cp310-win_amd64.whl
Size 665.9 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
6cf4141fa96e1374c1bdc6e32e9fda9a89ea787851ecd632dca9cdb81df33daa
BLAKE2b-256 checksum
How to use checksums
9d23792799535fc387b840d7a19a97b887d7cf9d1a32da9bb1763d44b93d976f
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.2-cp39-cp39-win_arm64.whl

Download URL winloop-0.7.2-cp39-cp39-win_arm64.whl
Size 601.4 kB
Tags CPython 3.9 Windows ARM64
SHA-256 checksum
How to use checksums
8c00d88b95bcc739c4c5b3a750440d6ee8ea6b059f8bde2bf2f4ee7dd02bb3b8
BLAKE2b-256 checksum
How to use checksums
b417369ee40e31de426b01ded6df1b66ea7aba22b562b863d417dea15df1532f
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.2-cp39-cp39-win_amd64.whl

Download URL winloop-0.7.2-cp39-cp39-win_amd64.whl
Size 667.2 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
dd46e5f710aeb10228fc7050fb947a9292581b21ca57292622e2f16e6dba3c54
BLAKE2b-256 checksum
How to use checksums
fe48293569f59fbc9ab588f880bef19620b05047df9d03ac0ef35ae76ef3e240
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

This release

0.7.2 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