Tradução do artigo original escrito por Yeray Diaz para o hackernoon: AsyncIO for the working Python developer

由Yaray Diaz para o hackernoon撰写的原始文章:适用于Python开发人员的AsyncIO

Eu me lembro do exato momento em que eu pensei, “Uau, isso está lento, aposto que se eu pudesse paralelizar essas chamadas isso voaria!” e então, 3 dias após, eu olhei para o meu código e não pude reconhece-lo, havia se transformado em um misturado de chamadas para threading e funções da biblioteca processing.

Eu me lembro do exatomomento em que eu pensei,“ U,Issoestálento,aposto que se eu pudesse paralelizar essas chamadas isso voaria!” 从3年前开始,从头到尾重新加工,从头到尾进行螺纹加工,并进行书目处理。

Então encontrei o asyncio, e tudo mudou!

Entcono encontrei o asyncio和e tudo mudou!



Se você não conhece, asyncio é o novo módulo de concorrência introduzido no Python 3.4. É projetado para usar coroutines e futures para simplificar a programação assíncrona e tornar o código tão legível quanto o código síncrono simplesmente por não haver callbacks.

语法,异步语言和Python 3.4版本。 协程和期货的简化程序很简单,它会回调回调程序。

Eu também me lembro que enquanto eu estava naquela busca pelo paralelismo inúmeras opções estavam disponíveis, mas uma se destacou. Era rápida, fácil de aprender e muito bem escrita: A excelente biblioteca gevent. Eu cheguei até ela lendo o encantador tutorial mão na massa: Gevent for the Working Python Developer, escrito por uma sensacional comunidade de usuários, uma ótima introdução não apenas ao gevent mas ao conceito de concorrência em geral, e você também deveria dar uma lida.

您可以在其他地方找到自己的名字,也可以在自己的网站上找到自己的名字。 《时代》杂志,一部优秀的《圣经》 杂志 。 Eu chegueiatéela lendo o encantador教程: 工作的Python开发人员的 Gevent,escrito por uma sensacional comunidade deusuários,umaótimaintroduçãonãapenas ao gevent mas ao conceito deéconcorrêndareméalal,

Eu gostei tanto do tutorial que decidi usa-lo como template para escrever sobre o AsyncIO.

Eu gostei tanto做AsyncIO教程。

Aviso Rápido: Isto não é um artigo sobre gevent X asyncio, O Nathan Road escreveu a respeito das diferenças e similaridades entre esses 2 se você estiver interessado.

阿维索·拉皮多(AvisoRápido):I stonãoéum artigo sobre gevent X asyncio,O Nathan Road escreveu a respeito dasdiferençaseentidases entre essere 2 sevocêestiver interessado。

Uma nota a respeito do código neste tutorial, você deve ter lido que no Python 3.5 uma nova sintaxe foi introduzida, especialmente para coroutines, eu estou intencionalmente não utilizando esta nova sintaxe neste texto pois desta forma acredito que fica mais fácil para assimilar as coroutinas com generators. Mas você pode encontrar versões dos exemplos usando esta nova sintaxe no github.

Us nota a respeito docódigoneste tutorial,python uma nova s​​intaxe foi introduzida,especialmente para coroutines,eu estou intencionalmentenãoutilizando esta nova nova s​​intaxe neste texto pois desta corma finaféas as asa fadito发电机。 Masvocêpode encontrarversõesdos exemplos usando esta nova s​​intaxe no github 。

Eu sei que você já deve estar ansioso mas antes de mergulharmos eu gostaria de primeiramente falar rapidamente sobre alguns conceitos que talvez não lhe sejam familiares.

熟悉的情况下,紧急情况发生的原因就由塔尔维斯和塔尔维斯·纳尔维斯·阿尔古斯·康塞洛伊斯·塔尔维斯·纳尔·奥古斯塔·马修·安德鲁斯·德·埃塞俄比亚人组成。

线程,循环,协程和期货 (Threads, loops, coroutines and futures)

Threads são uma ferramenta comum e a maioria dos desenvolvedores já ouviu falar ou já usou. Entretanto o asyncio usa de estruturas um pouco diferentes: event loops, coroutines e futures.

线程sãouma ferramenta comum ea maioria dos desenvolvedoresjáouviu falar oujáusou。 与不同的企业建立联系:事件循环,协程和期货。

  • Um event loop gerencia e distribui a execução de diferentes tarefas. Ele mantém um registro de tarefas (coroutines) e distribui o fluxo de execução entre elas.
  • As coroutines são geradores Python (generators), que quando há a ocorrência do yield libera o controle do fluxo de volta ao event loop. Uma coroutine precisa estar programada para ser executada usando o event loop, para fazer isso criamos uma tarefa do tipo future.
  • E um future é um objeto que representa o resultado de uma tarefa que pode, ou não, ter sido executada. Este resultado pode ser uma Exception.
  • UM 事件循环分发和执行tarefas。 协同操作的电子分发和分发。
  • 正如协程 sãogeradores Python(生成器)一样,quanquan确实会产生 libera或controle并导致fluxo de volta a事件循环。 乌玛协程预告片事件执行程序,事件组, 未来事件
  • 可能会在 sido executada的ounão的结果中代表您的最终结果。 Este resultado pode ser uma异常。

Entendeu? simples né? vamos mergulhar neste conceito!

Entendeu? 简单吗? vamos mergulhar嵌套conceito!

Execuçãosíncrona和Execuçãoassíncrona (Execução síncrona e Execução assíncrona)

Em Concorrência não é paralelismo, é melhor! o Rob Pike falou uma coisa que fez um click na minha cabeça: Dividir tarefas em sub-tarefas concorrentes já é o suficiente para permitir o paralelismo. Mas é o fato de programar/agendar a execução dessas sub-tarefas que realmente cria o paralelismo.

EmConcorrêncianãoéparalelismo,émelhor! o请按以下步骤操作:取消对divrefir tarefas或sub-tarefas的许可,以充分准予准许可或paralelismo。 计划/议事日程管理组织,执行副议事程序。

O ASyncIO faz exatamente isso, você pode estruturar o seu código em sub-tarefas definidas como coroutines e isso te permite programar a execução da maneira que desejar, incluindo a forma simultânea. As Corountines contém pontos de vazão demarcados com a palavra yield onde definimos onde uma troca de contexto poderia ocorrer caso existam outras tarefas pendentes, mas que não irá ocorrer caso não existam outras tarefas.

øASYNCIO FAZ exatamente ISSO,颇得VOCEøestruturar SEUcódigoEM子tarefas definidas como的协程ËISSO TE permite programar一个execução哒maneira阙desejar,incluindo一个形式上simultânea。 作为Corountinescontém奔涛德vazãodemarcados COM一个palavra 产生 ONDE definimos ONDE UMA troca德contexto poderia ocorrer卡索existam outras tarefas决案件,MAS阙NAO IRA ocorrer卡索NAO existam outras tarefas。

Nota do tradutor: Em uma loja de doces há um funcionário empacotando balas, ao finalizar cada pacote ele o lacra e coloca na vitrine (YIELD), então ele dá uma olhada no balcão para ver se tem algum cliente para ser atendido, se tiver um cliente, então ele para de empacotar balas atende o pedido do cliente (troca de contexto). E só depois de terminar de > atender o cliente ele então volta a empacotar as balas, caso não tenha cliente a ser atendido ele simplesmente continua o trabalho de empacotamento. Podemos dizer que é um funcionário fazendo duas tarefas __. (responda nos comentários se é paralelamente ou concorrentemente)

交易者巴拉姆 (Em uma loja de docesháum)职能部门,巴拉迪奥(finalizar cada pacote ele o lacra e coloca na vitrine)( YIELD ),埃塞俄比亚dúuma olhada nobalcãopara ver se se temrative al客户,请与客户联系,并向客户发出邀请( troca de contexto )。 最终客户的身份就像巴拉斯一样,客户应从简单的连续性客户中获得权利。 Podemos dizer queééumfuncionáriofazendo duas tarefas __ 。 ( responda noscomentáriosseéparalelamente ou concorrentemente

Uma troca de contexto no asyncio representa o event loop passando o fluxo de controle da coroutine em execução para a próxima na fila de execução, ou seja, (Yielding).

乌玛troca德contexto没有ASYNCIO representa O事件循环passandoØfluxo DE CONTROLE DA协程EMexecução第一个玛呐菲拉德execução,欧seja,( 产生 )。

Veja um exemplo básico:

示例:

import asyncio@asyncio.coroutine
def empacotar_bala():print("Empacotando balas...")# parada para verificar se tem cliente no balcãoyield from asyncio.sleep(0)# troca de contextoprint("Explicitamente voltando a empacotar balas")@asyncio.coroutine
def atender_balcao():print("Explicitamente verificando se tem cliente no balcão...")yield from asyncio.sleep(0)print("Voltando a empacotar as balas")ioloop = asyncio.get_event_loop()  # Event Looptasks = [ioloop.create_task(empacotar_bala()),ioloop.create_task(atender_balcao())]wait_tasks = asyncio.wait(tasks)ioloop.run_until_complete(wait_tasks)ioloop.close()
import asyncio@asyncio.coroutine
def empacotar_bala():print("Empacotando balas...")# parada para verificar se tem cliente no balcãoyield from asyncio.sleep(0)# troca de contextoprint("Explicitamente voltando a empacotar balas")@asyncio.coroutine
def atender_balcao():print("Explicitamente verificando se tem cliente no balcão...")yield from asyncio.sleep(0)print("Voltando a empacotar as balas")ioloop = asyncio.get_event_loop()  # Event Looptasks = [ioloop.create_task(empacotar_bala()),ioloop.create_task(atender_balcao())]wait_tasks = asyncio.wait(tasks)ioloop.run_until_complete(wait_tasks)ioloop.close()
 

Execute:

执行:

  • Primeiramente nós declaramos duas tarefas simples com a intenção de serem executadas de maneira não bloqueante pois usamos a função sleep do asyncio.
  • Coroutines só podem ser chamadas por outras coroutines ou podem ser agrupadas em uma task para então serem enfileiradas, nós usamos a função create_task para fazer isso.
  • Então criamos lista contendo as 2 tasks e nós a combinamos em uma wait que é uma task que irá aguardar até que todas as tarefas enfileiradas terminem.
  • E finalmente nós programamos a wait para executar usando o event loop usando a função run_until_complete.
  • Primeiramente号declaramos杜阿斯tarefas simples COM一个intenção德SEREM executadas德maneira淖bloqueante的POI usamos一个função 睡眠做ASYNCIO。
  • 协同程序 SóPODEM SER chamadas POR outras协程欧PODEM SER agrupadas EM UMA 任务对entãoSEREM enfileiradas,第一个usamosfunçãocreate_task对FAZER ISSO。
  • Entãocriamos LISTA contendo为2个任务 Ë号一combinamos EM UMA 等待阙éUMA任务阙IRA aguardar吃阙托达作为tarefas enfileiradas terminem。
  • 最终编程可以使用等待执行的事件或事件循环来执行run_until_complete 函数

Ao usar yield from na coroutine empacotar_bala nós declaramos que a coroutine pode naquele momento passar o controle do fluxo de execução de volta para o event loop, neste caso o sleep ao terminar (note o sleep(0)) irá devolver o controle ao event loop que irá mudar de contexto, passando o controle de fluxo para a próxima coroutine agendada para execução: atender_balcao

协程empacotar_bala声明的产量,到协程窗格中的瞬时动量或事件循环的执行量 ,嵌套睡眠,在端点(请注意sleep(0))或事件发生时进行控制请在上下文中输入密码,并在执行程序的过程中控制通量: atender_balcao

Nota: O tradutor alterou os nomes das funções dos exemplos do artigo original para dar um significado mais fácil de ser interpretado em português mas mantendo a semântica e fluxo de execução dos códigos, todavia os originais estão no github.

注释:阿尔及利亚的传统贸易惯例,原始的解释权是由西班牙人解释的,并由多哥的执行人通货膨胀,托达维亚的原产地是美国。

Vamos agora simular duas tarefas bloqueantes gr1 e gr2, considere que há dois requests para serviços externos. Enquanto elas executam, uma terceira tarefa pode ser executada assíncronamente, como no seguinte exemplo:

Vamos agora simular duas tarefas bloqueantes gr1 e gr2,请考虑是否要求提供外部服务。 Enquanto elas executam,uma terceira tarefa pode ser executadaassíncronamente,como no seguinte示例:

import time
import asynciostart = time.time()def tic():return 'at %1.1f segundos' % (time.time() - start)@asyncio.coroutine
def gr1():# Demora a ser executada, mas não queremos esperarprint('gr1 iniciou a execução: {}'.format(tic()))yield from asyncio.sleep(2)print('gr1 terminou a execução: {}'.format(tic()))@asyncio.coroutine
def gr2():# Demora a ser executada, mas não queremos esperarprint('gr2 iniciou a execução: {}'.format(tic()))yield from asyncio.sleep(2)print('gr2 terminou a execução: {}'.format(tic()))@asyncio.coroutine
def gr3():print('Executando enquanto as outras estão bloqueadas: {}'.format(tic()))yield from asyncio.sleep(5)print('Pronto!')ioloop = asyncio.get_event_loop()
tasks = [ioloop.create_task(gr1()),ioloop.create_task(gr2()),ioloop.create_task(gr3())
]
ioloop.run_until_complete(asyncio.wait(tasks))
ioloop.close()
import time
import asynciostart = time.time()def tic():return 'at %1.1f segundos' % (time.time() - start)@asyncio.coroutine
def gr1():# Demora a ser executada, mas não queremos esperarprint('gr1 iniciou a execução: {}'.format(tic()))yield from asyncio.sleep(2)print('gr1 terminou a execução: {}'.format(tic()))@asyncio.coroutine
def gr2():# Demora a ser executada, mas não queremos esperarprint('gr2 iniciou a execução: {}'.format(tic()))yield from asyncio.sleep(2)print('gr2 terminou a execução: {}'.format(tic()))@asyncio.coroutine
def gr3():print('Executando enquanto as outras estão bloqueadas: {}'.format(tic()))yield from asyncio.sleep(5)print('Pronto!')ioloop = asyncio.get_event_loop()
tasks = [ioloop.create_task(gr1()),ioloop.create_task(gr2()),ioloop.create_task(gr3())
]
ioloop.run_until_complete(asyncio.wait(tasks))
ioloop.close()
 

Execute:

执行:

Perceba que na forma que o I/O loop faz o gerenciamento e programa a execução permite que o seu código, rodando em single thread possa operar de forma concorrente. Enquanto duas tarefas estavam bloqueadas uma terceira pode tomar o controle do fluxo de execução e ser executada de maneira assíncrona.

I / O循环可用于执行程序,并且可以单线程执行操作。 Enquanto杜阿斯tarefas estavam bloqueadas UMA特塞拉颇得托马尔 ØCONTROLE做fluxo德execuçãoËSER executada德maneiraassíncrona。

执行官 (Ordem de execução)

No mundo síncrono estamos acostumados a pensar de maneira linear. Se nós tivermos uma lista de tarefas que consomem diferente quantidade de tempo elas serão executadas na ordem em que foram chamadas.

没有一个线性的马萨诸塞州的马萨诸塞州。 临时禁令的执行情况不同,临时禁令被临时执行。

Porém, quando usamos concorrência nós precisamos estar cientes de que as tarefas terminam em tempos que diferem da ordem em que foram enfileiradas.

Porém,quando usamosconcorrêncianósprecisamos estar cientes de que as tarefas terminam em tempos que diferem da ordem em que foram enfileiradas。

import random
from time import sleep
import asynciodef task(pid):"""Uma tarefa não deterministica"""sleep(random.randint(0, 2) * 0.001)print('Task %s terminada' % pid)@asyncio.coroutine
def task_coro(pid):"""Uma tarefa deterministica"""yield from asyncio.sleep(random.randint(0, 2) * 0.001)print('Task %s terminada' % pid)def synchronous():for i in range(1, 10):task(i)@asyncio.coroutine
def asynchronous():tasks = [asyncio.async(task_coro(i)) for i in range(1, 10)]yield from asyncio.wait(tasks)print('Síncronamente:')
synchronous()ioloop = asyncio.get_event_loop()
print('Assíncronamente:')
ioloop.run_until_complete(asynchronous())ioloop.close()
import random
from time import sleep
import asynciodef task(pid):"""Uma tarefa não deterministica"""sleep(random.randint(0, 2) * 0.001)print('Task %s terminada' % pid)@asyncio.coroutine
def task_coro(pid):"""Uma tarefa deterministica"""yield from asyncio.sleep(random.randint(0, 2) * 0.001)print('Task %s terminada' % pid)def synchronous():for i in range(1, 10):task(i)@asyncio.coroutine
def asynchronous():tasks = [asyncio.async(task_coro(i)) for i in range(1, 10)]yield from asyncio.wait(tasks)print('Síncronamente:')
synchronous()ioloop = asyncio.get_event_loop()
print('Assíncronamente:')
ioloop.run_until_complete(asynchronous())ioloop.close()
 

Execute:

执行:

A saida será com certeza variada, pois cada task espera por uma quantidade randômica de tempo, mas repare que a ordem dos resultados é completamente diferente, mesmo tendo enfileirado em uma lista de tarefas na mesma ordem usando o mesmo range.

一个赛伊达血清COM certeza variada,兴趣点CADA任务埃斯佩拉POR UMA quantidaderandômica德的节奏,MAS repare阙一ORDEM DOS resultadosécompletamente diferente,mesmo天童enfileirado EM UMA LISTA德tarefas呐MESMA ORDEM山岛Ømesmo 范围

Outro detalhe é que tivemos que uma versão em coroutine da nossa simples função. É importante entender que o asyncio não faz com que as coisas se transformarem magicamente em não bloqueantes.

简单和实用的协同作用。 重要的竞争者是非凡的魔术师

O AsyncIO está por enquanto sozinho na biblioteca padrão do Python 3 enquanto todos outros módulos oferecem apenas funcionalidades bloqueantes.

请参阅Python 3的完整说明,而不是功能化的功能。

Você pode usar o módulo concurrent.futures para agrupar tarefas bloqueantes em uma thread ou um processo e então retornar um Future que o asyncio pode utilizar. Os mesmos exemplos utilizando threads podem ser encontrados no github

VOCE颇得城市搜救Ø模concurrent.futures对agrupar tarefas bloqueantes EM UMA线程OU UM processoËentãoretornar嗯未来阙ØASYNCIO颇得utilizar。 操作系统mesmos exemplos utilizando线程podem ser encontrados no github

Esta é provavelmente a maior desvantagem ao usar asyncio neste momento, porém existe uma série de bibliotecas para diferentes tarefas e serviços que já estão disponíveis de maneira não bloqueante.

从根本上来说,可以立即获得优等的待遇,并且可以在不符合要求的情况下存在争议。



Uma tarefa bloqueante bastante comum é coletar dados de um serviço HTTP. Para isso vou usar a excelente biblioteca aiohttp que efetua chamadas não bloqueantes a serviços HTTP. Neste exemplo vamos coletar dados da API pública do Github e ler apenas o valor de Date do responde header.

HTTP的Uma tarefa bloqueante bastante comum和coletar dados de umserviço。 第ISSO VOU USAR一个EXCELENTE藏书aiohttp阙efetua chamadas淖bloqueantes一个SERVICOS HTTP。 Nested exemplo vamos coletar dados da APIpúblicado Github e ler apenas o valor de Date do responsee 标头

import time
import urllib.request
import asyncio
import aiohttpURL = 'https://api.github.com/events'
MAX_CLIENTS = 3def fetch_sync(pid):print('Captura síncrona {} iniciou'.format(pid))start = time.time()response = urllib.request.urlopen(URL)datetime = response.getheader('Date')print('Processo {}: {}, demorou: {:.2f} segundos'.format(pid, datetime, time.time() - start))return datetime@asyncio.coroutine
def fetch_async(pid):print('Captura assíncrona {} iniciou'.format(pid))start = time.time()response = yield from aiohttp.request('GET', URL)datetime = response.headers.get('Date')print('Processo {}: {}, demorou: {:.2f} segundos'.format(pid, datetime, time.time() - start))response.close()return datetimedef synchronous():start = time.time()for i in range(1, MAX_CLIENTS + 1):fetch_sync(i)print("Processo demorou: {:.2f} segundos".format(time.time() - start))@asyncio.coroutine
def asynchronous():start = time.time()tasks = [asyncio.ensure_future(fetch_async(i)) for i in range(1, MAX_CLIENTS + 1)]yield from asyncio.wait(tasks)print("Processo demorou: {:.2f} segundos".format(time.time() - start))print('Sincrono:')
synchronous()print('Assíncrono:')
ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
import time
import urllib.request
import asyncio
import aiohttpURL = 'https://api.github.com/events'
MAX_CLIENTS = 3def fetch_sync(pid):print('Captura síncrona {} iniciou'.format(pid))start = time.time()response = urllib.request.urlopen(URL)datetime = response.getheader('Date')print('Processo {}: {}, demorou: {:.2f} segundos'.format(pid, datetime, time.time() - start))return datetime@asyncio.coroutine
def fetch_async(pid):print('Captura assíncrona {} iniciou'.format(pid))start = time.time()response = yield from aiohttp.request('GET', URL)datetime = response.headers.get('Date')print('Processo {}: {}, demorou: {:.2f} segundos'.format(pid, datetime, time.time() - start))response.close()return datetimedef synchronous():start = time.time()for i in range(1, MAX_CLIENTS + 1):fetch_sync(i)print("Processo demorou: {:.2f} segundos".format(time.time() - start))@asyncio.coroutine
def asynchronous():start = time.time()tasks = [asyncio.ensure_future(fetch_async(i)) for i in range(1, MAX_CLIENTS + 1)]yield from asyncio.wait(tasks)print("Processo demorou: {:.2f} segundos".format(time.time() - start))print('Sincrono:')
synchronous()print('Assíncrono:')
ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
 

Execute:

执行:

Nota: requer Python 3.4.4+ caso contrário cairá em exception

注意:请重新获取Python 3.4.4+的casocontráriocairáem异常

Primeiramente, repare na diferença de tempo, usando chamadas assíncronas nós efetuamos as requisições ao serviço HTTP exatamente ao mesmo tempo (13:10:12). Como falado anteriormente, cada requisição passou (yield) o fluxo de controle para a próxima e retornou quando foi completada.

Primeiramente,tempare的副本,usando chamadasassíncronasnósefetuamos的必要性,以及HTTP评估的必要性(13:10:12)。 科莫法拉第前部法院,法院的通缉令( 产量 )或补全法。

Resultando no fato de que requisitar e capturar os resultados de todos as tarefas demorou o mesmo tempo que a requisição mais lenta! Veja o tempo no log 0.54 segundos para a requisição mais lenta (processo 1) e é exatamente o mesmo tempo que se passou para processar todos os 3 requests, Legal né? (enquanto a parte de I/O daquela tarefa lenta estava bloqueada, as outras puderam ser executadas simultaneamente).

结果必不可少,结果必不可少,因为它是必需品! 不需要记录日志0.54保留原始请求(处理1)和执行临时请求3的请求,合法吗? (将I / O daquela tarefa lenta estava bloqueada分配给其他人,因为它同时适用于executadas simultaneamente)。

Agora veja como o código é similar ao da versão síncrona! é praticamente o mesmo código! As diferenças principais são por conta das diferenças de implementações das bibliotecas usadas e a parte da criação das tasks e a espera para elas terminarem.

Agora veja como ocódigoé相似aoversãosíncrona! épraticamente o mesmocódigo! 作为实施原则的基本原则,在执行任务的过程中,无论是在任务期限上还是在实施过程中,都必须遵守。

Criandoconcorrência (Criando concorrência)

Até então estamos usando uma única abordagem de criar e requisitar resultados de coroutines, criar uma lista de tasks e esperar que elas terminem.

共同需求的最终结果, 协同 任务的共同作用清单。

Mas as coroutines podem ser programadas para serem executadas e requisitar resultados em maneiras diferentes. Imagine um cenário onde precisamos processar os resultados de uma chamada HTTP GET assim que ela é requisitada, o processo é na verdade similar ao que fizemos no exemplo anterior.

Mas是协程程序,程序执行是必需的,结果是不同的。 试想一下,由于预想的处理过程和处理结果,HTTP GET的请求和处理过程类似,没有任何先例。

import time
import random
import asyncio
import aiohttpURL = 'https://api.github.com/events'
MAX_CLIENTS = 3@asyncio.coroutine
def fetch_async(pid):start = time.time()sleepy_time = random.randint(2, 5)print('Processo assincrono {} iniciou, esperando por {} segundos'.format(pid, sleepy_time))yield from asyncio.sleep(sleepy_time)response = yield from aiohttp.request('GET', URL)datetime = response.headers.get('Date')response.close()return 'Processo {}: {}, demorou: {:.2f} segundos'.format(pid, datetime, time.time() - start)@asyncio.coroutine
def asynchronous():start = time.time()futures = [fetch_async(i) for i in range(1, MAX_CLIENTS + 1)]for i, future in enumerate(asyncio.as_completed(futures)):result = yield from futureprint('{} {}'.format(">>" * (i + 1), result))print("Processo demorou: {:.2f} segundos".format(time.time() - start))ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
import time
import random
import asyncio
import aiohttpURL = 'https://api.github.com/events'
MAX_CLIENTS = 3@asyncio.coroutine
def fetch_async(pid):start = time.time()sleepy_time = random.randint(2, 5)print('Processo assincrono {} iniciou, esperando por {} segundos'.format(pid, sleepy_time))yield from asyncio.sleep(sleepy_time)response = yield from aiohttp.request('GET', URL)datetime = response.headers.get('Date')response.close()return 'Processo {}: {}, demorou: {:.2f} segundos'.format(pid, datetime, time.time() - start)@asyncio.coroutine
def asynchronous():start = time.time()futures = [fetch_async(i) for i in range(1, MAX_CLIENTS + 1)]for i, future in enumerate(asyncio.as_completed(futures)):result = yield from futureprint('{} {}'.format(">>" * (i + 1), result))print("Processo demorou: {:.2f} segundos".format(time.time() - start))ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
 

Execute

执行

Repare no deslocamento >> e no tempo de cada chamada, elas foram programadas ao mesmo tempo, os resultados chegam fora de ordem e são processados assim que chegam.

副本>>到 cada chamada的时间,从esmo tempo到la s foram的程序,到process的asas到chegam的命令。

Este código é um pouco diferente, estamos agrupando as coroutines em uma lista, cada uma para ser agendada e executada. a função as_completed retorna um iterador que irá gerar (YIELD) um future completo assim que a tarefa estiver terminada. Muito legal né? aliás, as funções as_completed e wait são ambas originalmente parte do modulo concurrent.futures

Estecódigoéum pouco diferente,estamos agrupando as coroutines em uma lista,cada uma para ser议程和executada。 一个funçãoas_completed retorna嗯iterador阙IRA基拉( 收益率 )嗯未来COMPLETO assim阙一tarefa estiver terminada。 Muito LegalNé? 别名,如完成的功能等待原件的模数并发。



Vamos pegar um outro exemplo, imagine que você está tentando consultar o seu endereço de IP público atual em seu programa. Existem alguns serviços que fornecem essa informação mas você não tem certeza se estarão acessíveis no momento da execução. Você não quer checar cada um deles sequencialmente, então, é preferível efetuar requisições concorrentes para cada um dos serviços e utilizar aquele que responder mais rapidamente, ok? Ok!

举例来说,Vamos pegar um是您的最佳选择,请设想一下IP公用事业的临时顾问。 存在的自动售货机可能会因无法立即执行任何操作而给您的信息造成不利影响。 否,请取消您的要求,以便继续使用本手册,可以使用吗? 好!

Bom, acontece que nosso velho amigo wait recebe o parâmetro return_when para fazer exatamente isso. Estávamos ignorando o dado retornado pelo wait já que estávamos preocupados apenas em paralelizar as tarefas. Mas agora nós queremos pegar os resultados da coroutine, então usaremos dois conjuntos de futures, done e pending.

汜,acontece阙nosso韦柳AMIGO 等待 recebeØparâmetroreturn_when对FAZER exatamente ISSO。 Estávamosignorando o dado retornado pelo 等待 jáqueestávamospreocupados apenas em paralelizar作为tarefas。 马斯集会号queremos pegar OS resultados DA协程,entãousaremos的DOI conjuntos德期货 ē 悬而未决

from collections import namedtuple
import time
import asyncio
from concurrent.futures import FIRST_COMPLETED
import aiohttpService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))response = yield from aiohttp.request('GET', service.url)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()return '{} terminou com resultado: {}, demorou: {:.2f} segundos'.format(service.name, ip, time.time() - start)@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, pending = yield from asyncio.wait(futures, return_when=FIRST_COMPLETED)print(done.pop().result())ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
from collections import namedtuple
import time
import asyncio
from concurrent.futures import FIRST_COMPLETED
import aiohttpService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))response = yield from aiohttp.request('GET', service.url)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()return '{} terminou com resultado: {}, demorou: {:.2f} segundos'.format(service.name, ip, time.time() - start)@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, pending = yield from asyncio.wait(futures, return_when=FIRST_COMPLETED)print(done.pop().result())ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
 

Execute:

执行:

Espere, o que aconteceu aqui? O primeiro serviço respondeu com sucesso então o que são esses warnings?

埃斯佩雷,阿奎Tyk阿奎吗? 可能会警告或警告您需要警告吗?

Bem, nós agendamos duas tarefas mas não permitimos que as duas fossem completadas. o AsyncIO considera que é um bug e imprime um warning. Então queremos informar ao event loop que este era um comportamento esperado e não se preocupar com a segunda tarefa que ficou pendente. Como? que bom que perguntou.

Bem,duas fossem completadas的议事日程。 o AsyncIO考虑到错误警告。 Entrepãoqueremos informationar a event loop que este age um comportamento esperado enãose preocupar com segunda tarefa que ficou pendente。 科莫? bo邦Perl古图。

Estados do Futuro (Estados do Futuro)

(sobre o estado que um future está atualmente, não o estado que ele estará no futuro… você entendeu né!)

(您可以在未来的预算中找到自己的未来,不要在未来的任何时候中……动听吧!)

Eles são:

Elessão:

  • Pending
  • Running
  • Done
  • Cancelled
  • 待定
  • 跑步
  • 完成了
  • 取消

Simples assim, quando um future finaliza sua tarefa, esta tarefa irá retornar o resultado de volta para o future, se estiver em pending ou cancelled ele gera o erro InvalidStateError ou CancelledError, e finalmente se a coroutine gera o erro ele será re-gerado, o que significa o mesmo comportamento ao chamar exception. confira aqui

Simples assim,quando嗯未来finaliza SUA tarefa,ESTA tarefa IRA retornarØresultado德沃尔对Ø未来,SE estiver EM 未决的取消 ELE格拉Ø埃罗InvalidStateErrorCancelledError,电子finalmente SE协程格拉Ø埃罗ELE血清重新杰拉多, o具有重要意义,或属于chamar 异常 。 confira aqui

Você também pode usar .done, .cancelled e .running em uma Future para obter um booleano indicando o estado. Note que done significa simplesmente que o result irá retornar ou gerar um erro. Você pode explicitamente cancelar um Future chamando o método cancel, e isso é o que precisamos para resolver o warning anterior.

可以使用.done.canceled.running em uma进行语音广播,将来可以使用booleano indicando o estado。 注阙标志意义simplesmente阙Ø 导致 IRA retornar欧基拉嗯埃罗。 明确取消要求和取消取消要求 ,以免引起预警。

def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, pending = yield from asyncio.wait(futures, return_when=FIRST_COMPLETED)print(done.pop().result())for future in pending:future.cancel()
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, pending = yield from asyncio.wait(futures, return_when=FIRST_COMPLETED)print(done.pop().result())for future in pending:future.cancel()
 

e então

entent

Um bom resultado né!

嗯,结果!

Futures permitem injetar callbacks a serem executados quando entrarem no estado done caso você queira adicionar uma lógica adicional, ou se você não quiser usar o yield from e prefira o callback hell, (sério quer mesmo?)

期货 permitem injetar 回调一个SEREM executados quando entrarem没有ESTADO 卡索VOCE queira adicionar UMA逻adicional,OU SE VOCE NAO quiser城市搜救Ø 从产量 éprefiraØ 回调地狱 ,(里奥QUER mesmo?)

E você pode, para objetivos de unit-testing manualmente injetar o resultado ou uma exception a um Future.

在单元测试手册中,除了最终结果外,还需另加注解。

Gerenciamento de erros (Gerenciamento de erros)

O AsyncIO é sobre fazer código concorrente gerenciável e legível, e isto se torna óbio no que diz respeito ao tratamento de erros. Vamos voltar ao exemplo anterior para ilustrar isso.

或以正确的方式处理好所有的错误消息,然后再删除错误消息。 Vamos voltar例行性前位等位。

Imagine que queremos garantir que os 2 serviços retornaram o mesmo resultado, mas um dos serviços fica offline e não responde, podemos usar apenas o usual try… except

想象一下queremos garantir que os 2服务到mesmo resultado,离线mas um dosserviçosfica脱机,podemos usap apenas o通常尝试…除了

from collections import namedtuple
import time
import asyncio
from concurrent.futures import FIRST_COMPLETED
import aiohttpService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query'),Service('broken', 'http://este-servico-nao-funciona', 'ip')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))try:response = yield from aiohttp.request('GET', service.url)except:return "{} não está respondendo".format(service.name)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()return '{} terminou com resultado: {}, demorou: {:.2f} segundos'.format(service.name, ip, time.time() - start)@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, _ = yield from asyncio.wait(futures)for future in done:print(future.result())ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
from collections import namedtuple
import time
import asyncio
from concurrent.futures import FIRST_COMPLETED
import aiohttpService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query'),Service('broken', 'http://este-servico-nao-funciona', 'ip')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))try:response = yield from aiohttp.request('GET', service.url)except:return "{} não está respondendo".format(service.name)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()return '{} terminou com resultado: {}, demorou: {:.2f} segundos'.format(service.name, ip, time.time() - start)@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, _ = yield from asyncio.wait(futures)for future in done:print(future.result())ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
 

execute:

执行:

Também podemos tratar os erros enquanto processamos os resultados dos Futures em caso de algo não esperado acontecer (lembra que eu disse que os erros são re-gerados na coroutine).

Tambémpodemos tratar os erros enquanto processamos os resultados dos Futures em caso de algonãoesperado acontecer(lembra que eu disse que os errossãore-gerados na coroutine)。

from collections import namedtuple
import time
import asyncio
from concurrent.futures import FIRST_COMPLETED
import aiohttp
import tracebackService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query'),Service('broken', 'http://este-servico-nao-funciona', 'ip')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))try:response = yield from aiohttp.request('GET', service.url)except:return "{} não está respondendo".format(service.name)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()return '{} terminou com resultado: {}, demorou: {:.2f} segundos'.format(service.name, ip, time.time() - start)@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, _ = yield from asyncio.wait(futures)for future in done:try:print(future.result())except:print("Erro não esperado: {}".format(traceback.format_exc()))ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
from collections import namedtuple
import time
import asyncio
from concurrent.futures import FIRST_COMPLETED
import aiohttp
import tracebackService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query'),Service('broken', 'http://este-servico-nao-funciona', 'ip')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))try:response = yield from aiohttp.request('GET', service.url)except:return "{} não está respondendo".format(service.name)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()return '{} terminou com resultado: {}, demorou: {:.2f} segundos'.format(service.name, ip, time.time() - start)@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]done, _ = yield from asyncio.wait(futures)for future in done:try:print(future.result())except:print("Erro não esperado: {}".format(traceback.format_exc()))ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
 

Veja:

Veja:

Da mesma forma que agendar uma task e não esperar que ela termine é considerado um bug, agendar uma task e não recuperar possíveis erros também irá gerar um warning.

大事例会议议程,请注意问题,会议事例要恢复警告。

from collections import namedtuple
import time
import asyncio
import aiohttpService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'this-is-not-an-attr'),Service('borken', 'http://no-way-this-is-going-to-work.com/json', 'ip')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))try:response = yield from aiohttp.request('GET', service.url)except:print('{} is unresponsive'.format(service.name))else:json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()print('{} finished with result: {}, took: {:.2f} seconds'.format(service.name, ip, time.time() - start))@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]yield from asyncio.wait(futures)  # intentionally ignore resultsioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
from collections import namedtuple
import time
import asyncio
import aiohttpService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'this-is-not-an-attr'),Service('borken', 'http://no-way-this-is-going-to-work.com/json', 'ip')
)@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))try:response = yield from aiohttp.request('GET', service.url)except:print('{} is unresponsive'.format(service.name))else:json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()print('{} finished with result: {}, took: {:.2f} seconds'.format(service.name, ip, time.time() - start))@asyncio.coroutine
def asynchronous():futures = [fetch_ip(service) for service in SERVICES]yield from asyncio.wait(futures)  # intentionally ignore resultsioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous())
ioloop.close()
 

execute:

执行:

Se parece muito com a saída do exemplo anterior, mas não contém os mínimos detalhes e mensagens do asyncio.

例行事前调查,事例不合时宜。

超时时间 (Timeouts)

E se nós não nos importarmos muito com o nosso IP? Imagine que é apenas um adicional ao nosso serviço, mas não importante, não queremos que o usuário fique esperando por este dado. Idealmente nós definimos um time-out para nossas tarefas não bloqueantes, e então continuamos nosso programa sem o atributo do IP já que neste exemplo não é tão importante.

否否重要否是否IP? 想象一下,重要的人,重要的人,以及用普通话在世界各地使用火药的人。 理想的超时超时时间,从头到尾都需要对IP进行永久性设置,以确保IP实例的重要性。

De novo descobrimos que wait tem o atributo que precisamos:

从头descobrimos阙等待 TEMØatributo阙precisamos:

import time
import random
import asyncio
import aiohttp
import argparse
from collections import namedtuple
from concurrent.futures import FIRST_COMPLETEDService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query'),
)DEFAULT_TIMEOUT = 0.01@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))yield from asyncio.sleep(random.randint(1, 3) * 0.1)try:response = yield from aiohttp.request('GET', service.url)except:return '{} is unresponsive'.format(service.name)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()print('{} finished with result: {}, took: {:.2f} seconds'.format(service.name, ip, time.time() - start))return ip@asyncio.coroutine
def asynchronous(timeout):response = {"message": "Result from asynchronous.","ip": "not available"}futures = [fetch_ip(service) for service in SERVICES]done, pending = yield from asyncio.wait(futures, timeout=timeout, return_when=FIRST_COMPLETED)for future in pending:future.cancel()for future in done:response["ip"] = future.result()print(response)parser = argparse.ArgumentParser()
parser.add_argument('-t', '--timeout',help='Timeout to use, defaults to {}'.format(DEFAULT_TIMEOUT),default=DEFAULT_TIMEOUT, type=float)
args = parser.parse_args()print("Using a {} timeout".format(args.timeout))
ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous(args.timeout))
ioloop.close()
import time
import random
import asyncio
import aiohttp
import argparse
from collections import namedtuple
from concurrent.futures import FIRST_COMPLETEDService = namedtuple('Service', ('name', 'url', 'ip_attr'))SERVICES = (Service('ipify', 'https://api.ipify.org?format=json', 'ip'),Service('ip-api', 'http://ip-api.com/json', 'query'),
)DEFAULT_TIMEOUT = 0.01@asyncio.coroutine
def fetch_ip(service):start = time.time()print('Fetching IP from {}'.format(service.name))yield from asyncio.sleep(random.randint(1, 3) * 0.1)try:response = yield from aiohttp.request('GET', service.url)except:return '{} is unresponsive'.format(service.name)json_response = yield from response.json()ip = json_response[service.ip_attr]response.close()print('{} finished with result: {}, took: {:.2f} seconds'.format(service.name, ip, time.time() - start))return ip@asyncio.coroutine
def asynchronous(timeout):response = {"message": "Result from asynchronous.","ip": "not available"}futures = [fetch_ip(service) for service in SERVICES]done, pending = yield from asyncio.wait(futures, timeout=timeout, return_when=FIRST_COMPLETED)for future in pending:future.cancel()for future in done:response["ip"] = future.result()print(response)parser = argparse.ArgumentParser()
parser.add_argument('-t', '--timeout',help='Timeout to use, defaults to {}'.format(DEFAULT_TIMEOUT),default=DEFAULT_TIMEOUT, type=float)
args = parser.parse_args()print("Using a {} timeout".format(args.timeout))
ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(asynchronous(args.timeout))
ioloop.close()
 

Repare no argumento timeout, também adicionamos um parâmetro de linha de comando para testar mais facilmente o que acontecerá se deixarmos a requisição ocorrer algumas vezes. Também adicionei um tempo randomico de slepp só para garantir que as coisas não aconteçam tão rápido que a gente nem perceba.

请勿重复超时 ,禁止向用户发送或删除需要帮助的人的座谈会贴图。 随身携带的淡淡淡淡的淡淡的淡淡的淡淡的淡淡的淡咖啡。

Conclusão (Conclusão)

Asyncio aumentou meu já enorme amor por Python. Para ser absolutamente honesto eu me apaixonei pelas coroutines em Python quando conheci o Tornado mas o asyncio conseguiu unir o melhor desta abordagem junto com excelentes bibliotecas de concorrência. E muito foi feito para que outras bibliotecas possam usar o IO loop, então se você está usando o Tornado, você também pode usa-lo com bibliotecas feitas para o asyncio!

使用Python进行异步处理。 绝对诚实的人可以在python程序包中找到自己的名字,或者在Python上充分理解Tornado mas或asyncio conseguiu,而在melhor desta abordagem junto com方面则表现出色。 从IO循环中获取更多信息,从IO循环中获取声音,从Tornado中获取声音,并以无意识的方式获取信息

E como eu disse anteriormente o maior problema por enquanto é a falta de bibliotecas e módulos que implementam o comportamento não bloqueante. Você pode achar que uma vasta quantidade de tecnologias já estabelecidas ainda não tenham uma versão não bloqueante para interagir com asyncio, ou que as existentes ainda estão jovens ou experimentais. Porém, O numero de bibliotexas está crescendo diariamente

请尽早从根本上解决问题,并最终履行一切义务。 从技术上说,以技术上的存在为基础,以其存在的意义为依据。 Porém, O numero de bibliotexasestácrescendo diariamente

confira este repo: https://github.com/aio-libs

confira este回购: https : //github.com/aio-libs

翻译自: https://www.pybloggers.com/2016/11/asyncio-o-futuro-do-python-mudou-completamente/

AsyncIO –可以完全完成Python的未来!相关推荐

  1. python编程未来就业方向有哪些?

    毋容置疑,python编程未来就业方向是多向的,有Linux运维.Python Web网站工程师和Python自动化检验等职位,因为我们现在已经迎来了大数据时代,Python编程语言成为了数据分析师的 ...

  2. python最终目标是什么_Python之父Guido谈Python的未来

    6月初,Python之父Guido van Rossum在今天的PyCon US大会上作了名为"Python Language"的演讲.近日,他又接受了IT媒体Infoworld的 ...

  3. python之父叫什么-Python之父谈Python的未来形式

    6月初,Python之父Guido van Rossum在今天的PyCon US大会上作了名为"Python Language"的演讲.近日,他又接受了IT媒体Infoworld的 ...

  4. 学python对数学要求高吗_人工智能的小男孩 大专学历的人没有数学基础想学习python技术未来能往大数据或人工智能方向进行职业发展吗?...

    内容由传智播客提供,电器吧机器人网提供人工智能的小男孩相关内容,小编烟酉为您整理并发布于人工智能栏目下,原标题:大专学历的人没有数学基础想学习python技术未来能往大数据或人工智能方向进行职业发展吗 ...

  5. 中国百强企业论Python的未来2021-03-15

    中国百强企业论Python的未来 计算机语言发展至今,已出现众多的编程语言.例如入门较难的C语言,相对通用的Java,适合初学者的Basic语言等. 但自从Python横空出世以来,以其简洁优美.功能 ...

  6. Python的未来在哪里?4年性能提升5倍,4.0也许永远不会来

    在最近的一次采访中,Python的创建者(现在在微软工作)吉多表示: Python 4.0也许永远都不会有!我和Python核心成员对Python 4.0一点都不兴趣! 如果你因此担心Python的未 ...

  7. guido python_Guido老爹谈Python的未来

    编程派微信号:codingpy 6月初,Python之父Guido van Rossum在今天的PyCon US大会上作了名为"Python Language"的演讲.近日,他又接 ...

  8. guido python_Python之父Guido谈Python的未来

    6月初,Python之父Guido van Rossum在今天的PyCon US大会上作了名为"Python Language"的演讲.近日,他又接受了IT媒体Infoworld的 ...

  9. python之父guido-Python之父Guido谈Python的未来

    6月初,Python之父Guido van Rossum在今天的PyCon US大会上作了名为"Python Language"的演讲.近日,他又接受了IT媒体Infoworld的 ...

最新文章

  1. vue前端表格插件_Grid.js - 跨框架的前端表格插件
  2. HIbernate——hibernate中的各种查询
  3. 计算机视觉完整学习大纲,来源于互联网,仅供大家参考~~~
  4. 用二分类神经网络估算多分类神经网络迭代次数的经验公式
  5. 《Linux内核原理与分析》第三周作业
  6. 无法打开网页~咋办?
  7. 第三次学JAVA再学不好就吃翔(part93)--LinkedHashMap
  8. UML-- plantUML安装
  9. .netcore excel导出回车换行_必须掌握的回车键Enter应用技巧,100%干货
  10. rzsz上传下载命令
  11. Javascript:call(),apply()和bind()
  12. 高级着色语言HLSL入门(2)
  13. Jquery .ajax方法分析(一)
  14. python输入税前工资打印税后工资-python-计算个人所得税
  15. Navicat Premium 15 for Mac(数据库管理)
  16. 2022.09 青少年软件编程(图形化) 等级考试试卷(四级)
  17. python可视化图表生成(二)
  18. linux黄颜色文件,了解 Linux 文件的颜色代码
  19. 超级IP哈利波特改编,网易这款刷爆朋友圈的手游究竟怎么样?
  20. GEDI学习笔记1:数据产品简介

热门文章

  1. 制作《王者荣耀》需要学习哪些技术?
  2. 保险公司数据信息机房,运维难度指数级增加?
  3. http常见状态码有哪些?
  4. 第5章 不要让线程成为脱缰的野马(Keeping your Threads on Leash) ----初始化一个线程...
  5. python0x452_Python(变量、数据类型)
  6. 字节小组长薪资被应届生员工倒挂7K,不把老员工当人?
  7. oracle中表和视图的区别,Oracle数据库中表与视图的应用
  8. 华为手机升级回退_EMUI4.0回退EMUI3.1!通过华为手机助手也能实现
  9. Android中启动一个服务,Android服务的两种启动方式
  10. 小黑小波比.git教程