我曾经在一个Python2系统上工作,该系统具有许多同步编写的自定义I / O代码,并使用线程进行了扩展。在某个时候,我们无法进一步扩展它,并意识到我们必须切换到异步编程。
@inlineCallbacks装饰器,该装饰器与其他一些库一样,使用生成器魔术有效地实现了协程。那是可以忍受的,但感觉有点片状。from gevent import monkey
monkey.patch_all()
Run Code Online (Sandbox Code Playgroud)
就像那样,您的所有标准I / O(套接字,数据库事务以及用纯Python编写的所有内容)实际上都是异步的,使用greenlet产生并在后台切换。
这不是完美的:
如今,Python 3更加流行,并且有了它-asyncio。就个人而言,我认为这很棒,但是最近有人问我,它比我们使用gevent做的更好吗?无法给出足够好的答案。
这听起来可能是主观的,但是我实际上是在寻找一个实际的用例,其中一个将大大优于另一个,或者允许另一个不这样做。到目前为止,这是我收集的注意事项:
就像我说的那样,gevent在Windows上非常受限制。再说一次,我所知道的大多数生产代码都在Linux上运行。
如果需要在Windows上运行,请使用asyncio。
Gevent无法猴子C扩展。但是,asyncio无法猴子修补任何东西。
想象一下,出现了一种新的数据库技术,并且您想使用它,但是它没有一个纯Python库,因此您无法将其与Gevent集成。问题是,当没有可以与asyncio集成的io *库时,您就像被困一样!当然,有工作线程和执行程序,但这不是重点,无论如何在两种情况下都一样好。
有人说这是个人喜好,但我认为可以说同步编程从本质上讲要比异步编程更容易(请考虑一下:您是否遇到过可以使用套接字的新手程序员,但是很难理解如何正确选择/投票,或考虑期货/承诺?您遇到过相反的情况吗?)。
无论如何,我们不要去那里。我想解决这一点,因为它经常出现(这是关于reddit的讨论),但是我真正要关注的是您有实际理由使用其中一种的情况。
Asyncio是标准库的一部分。这是巨大的:这意味着它得到了很好的维护,良好的记录,并且每个人都知道它并默认使用它。
但是,考虑到您需要使用Gevent的知识很少(并且它也得到很好的维护和记录),它似乎并不重要。因此,即使对于涉及期货的最复杂的方案,StackOverflow上也有多个答案,但根本不使用期货的可能性似乎也是可行的。
那么:asyncio盛行的一些具体用例是什么?当然,Guido和Python社区有充分的理由对此投入大量精力,甚至在语言中引入了新的关键字-我似乎找不到它们。
我正在使用Python 3.5和Django 1.10来运行开发服务器:
./manage.py runserver 0.0.0.0:8000
Run Code Online (Sandbox Code Playgroud)
在我的settings.py身上:
DEBUG = True
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
Run Code Online (Sandbox Code Playgroud)
和一个app目录,static其静态文件的子目录:
proj/
proj/
...
app/
static/
a.txt
...
static/
b.txt
Run Code Online (Sandbox Code Playgroud)
很标准.
但是:Django没有服务的STATIC_ROOT时候DEBUG = True.它返回app/static/a.txt的/static/a.txt还好,但不static/b.txt为/static/b.txt.
修改settings.py为:
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
Run Code Online (Sandbox Code Playgroud)
作品 - 但我必须发表评论STATIC_ROOT(否则Django抱怨它不能进入STATICFILES_DIRS).
现在,我不能只是"使用不同的外部静态目录",例如static2,因为我正在使用django-sass-processor,它将.sass文件编译成.css文件,并将这些.css文件放入STATIC_ROOT(正如我所说,这是无法访问的).
我试过的事情:
设置NGINX以服务该目录(如在生产环境中).工作,但必须有另一种方式.
配置 …
当我发现一些奇怪的东西时,我正在玩新的和删除操作符重载.
我有:
void* operator new(size_t size)
{
std::cout << "Allocating memory..." << std::endl;
void* p = malloc(size);
if (NULL == p)
{
throw std::bad_alloc();
}
return p;
}
Run Code Online (Sandbox Code Playgroud)当我做:
int main()
{
int* x = new int(1);
std::cout << *x << std::endl;
delete x;
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
一切都按预期工作,我得到:
Allocating memory...
1
Run Code Online (Sandbox Code Playgroud)但当我这样做时:
int main()
{
std::string* s = new std::string("Hello world");
std::cout << *s << std::endl;
delete s;
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
我明白了:
Allocating memory...
Allocating memory...
Hello world
Run Code Online (Sandbox Code Playgroud)事实上,当我这样做时:
int …Run Code Online (Sandbox Code Playgroud)setup.py通常取决于几个外部文件,尤其是README.mdfor long_description,也许是VERSIONfor version。例如
root = os.path.dirname(os.path.abspath(__file__))
setuptools.setup(
name = 'package',
version = open(os.path.join(root, 'VERSION')).read().strip(),
description = 'A Simple Package',
long_description = open(os.path.join(root, 'README.md')).read().strip(),
# ...
)
Run Code Online (Sandbox Code Playgroud)
但是,当尝试tox在这样的程序包上运行测试时,出现以下错误:
ERROR: invocation failed (exit code 1), logfile:
.tox/py36/log/py36-6.log
ERROR: actionid: py36
msg: installpkg
cmdargs:
['.tox/py36/bin/pip', 'install', '-U', '--no-deps', '.tox/dist/package-0.1.0.zip']
Processing ./.tox/dist/package-0.1.0.zip
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "setup.py", line 10, in …Run Code Online (Sandbox Code Playgroud)