小编wvx*_*xvw的帖子

asyncio实际上如何工作?

这个问题是由我的另一个问题推动的:如何在cdef中等待?

网上有大量的文章和博客文章asyncio,但它们都非常肤浅.我找不到任何有关如何asyncio实际实现的信息,以及I/O异步的原因.我试图阅读源代码,但它是成千上万行不是最高级别的C代码,其中很多处理辅助对象,但最重要的是,很难在Python语法和它将翻译的C代码之间建立连接成.

Asycnio自己的文档甚至没那么有用.没有关于它是如何工作的信息,只有关于如何使用它的一些指导,这些指导有时也会误导/写得很差.

我熟悉Go的coroutines实现,并且希望Python做同样的事情.如果是这种情况,我在上面链接的帖子中出现的代码就可以了.既然没有,我现在正试图找出原因.到目前为止我最好的猜测如下,请纠正我错在哪里:

  1. 表单的过程定义async def foo(): ...实际上被解释为类继承的方法coroutine.
  2. 也许,async def实际上是通过await语句拆分成多个方法,其中调用这些方法的对象能够跟踪到目前为止通过执行所做的进度.
  3. 如果上述情况属实,那么,从本质上讲,协程的执行归结为一些全局管理器调用协程对象的方法(循环?).
  4. 全局管理器以某种方式(如何?)了解I/O操作何时由Python(仅?)代码执行,并且能够在当前执行方法放弃控制之后选择一个待执行的协程方法执行(命中await语句) ).

换句话说,这是我尝试将某些asyncio语法"贬低"为更容易理解的东西:

async def coro(name):
    print('before', name)
    await asyncio.sleep()
    print('after', name)

asyncio.gather(coro('first'), coro('second'))

# translated from async def coro(name)
class Coro(coroutine):
    def before(self, name):
        print('before', name)

    def after(self, name):
        print('after', name)

    def __init__(self, name):
        self.name = name
        self.parts = self.before, self.after
        self.pos = 0

    def __call__():
        self.parts[self.pos](self.name)
        self.pos += 1

    def …
Run Code Online (Sandbox Code Playgroud)

python python-3.x python-asyncio

64
推荐指数
5
解决办法
1万
查看次数

RuntimeError:此事件循环已在python中运行

我想我得到了这个错误,因为我的代码调用了asyncio.get_event_loop().run_until_complete(foo())两次.从foo()第二次调用函数开始foo().我的问题是:为什么这会成为问题?我为什么要关心这个循环在运行?


对这个问题进行了编辑,我认为这个编辑模糊了(有些人更喜欢遵循规则而不理解它们,因此从标题中删除了"非法"字样).不幸的是,这会造成混乱.

我不会对错误提出这一事实感到惊讶.我可以追溯到asyncio源头,看看这个图书馆的作者想要这样做,那里没有神秘感.令人费解的部分原因在于库的作者认为在循环已经运行时从事件循环中请求运行某些函数是非法的.

我们可以将问题简化为两个这样的调用,通过案例分析,我们将看到这三种可能性:

  1. 两种功能都不会终止.
  2. 其中一个功能最终终止.
  3. 这两个功能最终终止.

现在,是否有任何明智的行为可以解决所有三种情况?对我而言,显而易见的是,这里可能存在或可能存在多种理智行为.例如:

  1. 没有什么特别的,两个函数的执行是交错的,并且它们会像预期的那样永远运行.
  2. 循环不会将控制权返回run_until_complete()到第二个函数完成之后的第一个实例之后的代码(因此不会run_until_complete()执行后面的代码.
  3. 在最后一个函数终止之后,循环将控制权返回给第一个代码对象,该对象调用run_until_complete忽略所有其他调用站点.

现在,我可以理解这种行为可能不是每个人都想要的.但是,由于这个库决定让程序员控制启动/停止事件循环,它还应该满足这些决策的后果.使多次启动相同循环成为错误会使库代码无法执行此操作,从而降低了库利用的质量和实用性asyncio(例如,确实如此aiohttp).

python python-asyncio

25
推荐指数
6
解决办法
3万
查看次数

如何取消公开(撤消公开)服务?

在Kubernetes中,可以通过运行使集群中的服务可从外部访问kubectl expose deployment.为什么部署而不是服务超出了我对傻瓜的理解.除此之外,我希望之后能够撤消此操作.想想一个场景,我需要访问通常只能在集群内部访问的服务以进行调试,然后恢复原始状态.

有没有办法做到这一点,删除部署并重新创建它?


PS.实际上删除服务和部署没有帮助.使用相同名称重新创建服务和部署将导致服务被公开.

service kubernetes

14
推荐指数
1
解决办法
6098
查看次数

google.protobuf.StringValue有什么意义?

我最近在Google的包装中遇到了各种各样的包装器protobuf。我正在努力想象用例。任何人都可以阐明:这些问题打算解决什么问题?

这是文档链接之一:https : //developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/string-value(它什么也没说用于)。

这与简单string类型在行为上会有所不同的一件事是,此字段的写入效率较低(几个额外的字节,外加冗余的内存分配)。对于其他包装器而言,情况更糟,因为repeated这些字段的变体编写效率低下(Google的Protobuf官方序列化器不支持packed非数字类型的编码)。

似乎都不是可取的。那么,这是怎么回事?

protocol-buffers

11
推荐指数
2
解决办法
3274
查看次数

当从模块导入特征时,py.test处理pylint和flake8

所以,我大致有这个代码:

from .fixtures import some_fixture


def test_whatever(some_fixture):
    print(some_fixture)
Run Code Online (Sandbox Code Playgroud)

我得到两个警告flake8:

F401'.fixtures.some_fixture'导入但未使用

F811从第1行重新定义未使用的'some_fixture'

我不打算在任何地方移动灯具,但是"装饰"每个测试定义和每个导入noqapylint评论似乎是一个非常悲伤和无色的生活(特别是有时它会使一个合法的警告沉默,当一个夹具不是真的用过).

我还可以做些什么?

python pytest

10
推荐指数
2
解决办法
1081
查看次数

如何在 cdef 中等待?

我有这个 Cython 代码(简化):

class Callback:
    async def foo(self):
        print('called')

cdef void call_foo(void* callback):
    print('call_foo')
    asyncio.wait_for(<object>callback.foo())

async def py_call_foo():
    call_foo(Callback())

async def example():
    loop.run_until_complete(py_call_foo())
Run Code Online (Sandbox Code Playgroud)

但是会发生什么:我得到RuntimeWarning: coroutine Callback.foo was never awaited. 而且,事实上,它从未被调用过。然而,call_foo被称为。

知道发生了什么/如何让它真正等待Callback.foo完成吗?


扩大的视野

在上面的示例中,缺少一些重要的细节:特别是,从call_foo. 真正的项目设置是这样的:

  1. 有规则的 Bison 解析器。规则引用了特制的结构,我们称之为ParserState. 此结构包含对回调的引用,当规则匹配时,解析器会调用回调。

  2. 在 Cython 代码中,有一个类,我们称之为Parser,包的用户应该扩展它以制作他们的自定义解析器。这个类有一些方法,然后需要从ParserState.

  3. 解析应该是这样发生的:

    async def parse_file(file, parser):
        cdef ParserState state = allocate_parser_state(
            rule_callbacks,
            parser,
            file,
        )
        parse_with_bison(state)
    
    Run Code Online (Sandbox Code Playgroud)

回调具有一般形状:

ctypedef void(callback*)(char* text, void* parser)
Run Code Online (Sandbox Code Playgroud)

我不得不承认我不知道具体是如何asyncio实现的await …

python cython python-asyncio

7
推荐指数
1
解决办法
3084
查看次数

不能隐式地在共享库中包含runtime/cgo

下面我前面的问题,试图从这个执行所有相同的步骤时,现在我收到此错误的文章,因为我从围棋1.6.1升级到1.7.1去(我不能回去去,因为1.6.1尝试编译某些共享库时链接器崩溃.

我做了什么:

  1. 安装进去~/.go/go(后面称之为GOROOT).
  2. 编译libstd.so:

    GOROOT=~/.go/go GOPATH=~/tests go install -buildmode=shared -linkshared std
    
    Run Code Online (Sandbox Code Playgroud)
  3. 编译calc库:

    GOROOT=~/.go/go GOPATH=~/tests go install -a -x -buildmode=shared -linkshared calc
    
    Run Code Online (Sandbox Code Playgroud)
  4. 试图编译app:

    GOROOT=~/.go/go GOPATH=~/tests go build -a -x -linkshared -o app cashier
    
    Run Code Online (Sandbox Code Playgroud)

    并收到此错误:

    ~/.go/go/pkg/tool/linux_amd64/link: cannot implicitly include runtime/cgo in a shared library
    
    Run Code Online (Sandbox Code Playgroud)

我尝试CGO_ENABLED=0在环境之前重复这些步骤,但没有任何东西会以这种方式构建.给我这个错误:

imports runtime/cgo: C source files not allowed when not using cgo or SWIG: gcc_fatalf.c gcc_linux_amd64.c gcc_mmap.c gcc_util.c
Run Code Online (Sandbox Code Playgroud)

这是一个已知的错误?是否支持共享库?

build shared-libraries go

6
推荐指数
1
解决办法
1037
查看次数

Jenkins pipeline sh:始终使用 pipelinefail

有没有办法将sh步骤配置为始终像set -o pipefail已设置一样运行?

这个错误花了我几天的时间才发现......因为我认为这将是默认设置。

shell pipe jenkins jenkins-pipeline

6
推荐指数
0
解决办法
2218
查看次数

Linux for Windows 上的交叉编译扩展

我已经成功地在 Linux 上构建了一些使用 MinGW 进行 Python 扩展所必需的 DLL。沿着这些思路:

from setuptools.command.build_py import build_py

class BuildGo(build_py):

    def run(self):
        if # need to build windows binaries
            self.build_win()
        build_py.run(self)

    def build_win(self):
        if # compilers and toolchain available
            try:
                # builds extra libraries necessary for this extension
            except subprocess.CalledProcessError as e:
                print(e.stderr)
                raise
            try:
                result = subprocess.check_output([
                    'x86_64-w64-mingw32-gcc-win32',
                    '-shared',
                    '-pthread',
                    '-o',
                    EXTRA_DLL,
                    FAKE_WIN_BINDINGS,
                    ARCHIVE_GENERATED_IN_PREVIOUS_STEP,
                    '-lwinmm',
                    '-lntdll',
                    '-lws2_32',
                ])
                print(result)
            except subprocess.CalledProcessError as e:
                print(e.stderr)
                raise
Run Code Online (Sandbox Code Playgroud)

我现在希望我可以避免build_ext以同样痛苦的方式进行扩展,让它为 Windows 交叉编译 Cython 代码...我研究了“和”setuptools的优雅相互作用的深渊,在深渊有机会看到之前回到我身上...是否有一种方法可以只指定一些标志...例如所需平台的编译器名称和Python二进制文件...它就可以做到这一点?distutils …

python cross-compiling cython

6
推荐指数
1
解决办法
4475
查看次数

asyncio:投机等待多个期货

TL; 博士

我怎样才能从期货集合中等待任何未来,有选择地通知其他期货“不再需要它们”?


这就是我需要这个的原因。我想创建一种特殊的期货/任务来计时,并且可以与其他期货/任务一起使用以在它们累积超过某个超时(或在与此计时任务交互后被迫停止)时取消它们。如果您熟悉 Go,它有一个类似的概念,称为Context.

为了使这更具体,想象一下。您有一个典型的 HTTP 客户端。为了从 URL 请求页面,它需要连续执行几个可能永远阻塞的操作。例如,这些操作可以是:

  1. 分配一个套接字。
  2. 连接到服务器。
  3. 以多个块检索页面。
  4. 关闭连接。
  5. 解除分配套接字。

假设您允许整个操作需要一分钟。但是您也知道分配套接字的时间不应超过一毫秒,连接也可能需要一分钟,检索块也是如此。断开连接和资源释放应该需要几毫秒。

假设现在您必须在每个项目符号点上等待完全超时——嗯,您已经超过了两次配额。因此,您需要将每次调用的计算增量传递给其后继调用。此外,假设您无法释放套接字——好吧,没什么大不了的,应用程序可能会从此错误中恢复,因此您还需要区分各种超时。我想这可以这样写(在某些虚构的 Python 版本中):

async def http_request(context, url):
    socket = await min(allocate_socket(), context.timeout, socket_timeout)
    await min(socket.connect(), context.timeout, connect_timeout)
    async for chunk in min(socket.receive(), context.timeout, chunk_timeout):
        print(chunk)
    await min(socket.close(), context.timeout, close_timeout)
Run Code Online (Sandbox Code Playgroud)

python python-asyncio

5
推荐指数
1
解决办法
2670
查看次数