- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章python并发编程之多进程、多线程、异步和协程详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
最近学习python并发,于是对多进程、多线程、异步和协程做了个总结。 1、多线程 。
多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计算机,也可以通过不停地在不同线程的指令间切换,从而造成多线程同时运行的效果.
多线程相当于一个并发(concunrrency)系统。并发系统一般同时执行多个任务。如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步的问题,比如多线程火车售票系统:两个指令,一个指令检查票是否卖完,另一个指令,多个窗口同时卖票,可能出现卖出不存在的票.
在并发情况下,指令执行的先后顺序由内核决定。同一个线程内部,指令按照先后顺序执行,但不同线程之间的指令很难说清除哪一个会先执行。因此要考虑多线程同步的问题。同步(synchronization)是指在一定的时间内只允许某一个线程访问某个资源.
1、thread模块 。
2、threading模块 threading.Thread 创建一个线程.
给判断是否有余票和卖票,加上互斥锁,这样就不会造成一个线程刚判断没有余票,而另外一个线程就执行卖票操作.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#! /usr/bin/python
#-* coding: utf-8 -*
# __author__ ="tyomcat"
import
threading
import
time
import
os
def
booth(tid):
global
i
global
lock
while
True
:
lock.acquire()
if
i!
=
0
:
i
=
i
-
1
print
"窗口:"
,tid,
",剩余票数:"
,i
time.sleep(
1
)
else
:
print
"Thread_id"
,tid,
"No more tickets"
os._exit(
0
)
lock.release()
time.sleep(
1
)
i
=
100
lock
=
threading.Lock()
for
k
in
range
(
10
):
new_thread
=
threading.Thread(target
=
booth,args
=
(k,))
new_thread.start()
|
2、协程(又称微线程,纤程) 。
协程,与线程的抢占式调度不同,它是协作式调度。协程也是单线程,但是它能让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来.
1、协程在python中可以由生成器(generator)来实现.
首先要对生成器和yield有一个扎实的理解. 。
调用一个普通的python函数,一般是从函数的第一行代码开始执行,结束于return语句、异常或者函数执行(也可以认为是隐式地返回了None).
一旦函数将控制权交还给调用者,就意味着全部结束。而有时可以创建能产生一个序列的函数,来“保存自己的工作”,这就是生成器(使用了yield关键字的函数).
能够“产生一个序列”是因为函数并没有像通常意义那样返回。return隐含的意思是函数正将执行代码的控制权返回给函数被调用的地方。而"yield"的隐含意思是控制权的转移是临时和自愿的,我们的函数将来还会收回控制权.
看一下生产者/消费者的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#! /usr/bin/python
#-* coding: utf-8 -*
# __author__ ="tyomcat"
import
time
import
sys
# 生产者
def
produce(l):
i
=
0
while
1
:
if
i <
10
:
l.append(i)
yield
i
i
=
i
+
1
time.sleep(
1
)
else
:
return
# 消费者
def
consume(l):
p
=
produce(l)
while
1
:
try
:
p.
next
()
while
len
(l) >
0
:
print
l.pop()
except
StopIteration:
sys.exit(
0
)
if
__name__
=
=
"__main__"
:
l
=
[]
consume(l)
|
当程序执行到produce的yield i时,返回了一个generator并暂停执行,当我们在custom中调用p.next(),程序又返回到produce的yield i 继续执行,这样 l 中又append了元素,然后我们print l.pop(),直到p.next()引发了StopIteration异常.
2、Stackless Python 。
3、greenlet模块 。
基于greenlet的实现则性能仅次于Stackless Python,大致比Stackless Python慢一倍,比其他方案快接近一个数量级。其实greenlet不是一种真正的并发机制,而是在同一线程内,在不同函数的执行代码块之间切换,实施“你运行一会、我运行一会”,并且在进行切换时必须指定何时切换以及切换到哪.
4、eventlet模块 。
3、多进程 1、子进程(subprocess包) 。
在python中,通过subprocess包,fork一个子进程,并运行外部程序.
调用系统的命令的时候,最先考虑的os模块。用os.system()和os.popen()来进行操作。但是这两个命令过于简单,不能完成一些复杂的操作,如给运行的命令提供输入或者读取命令的输出,判断该命令的运行状态,管理多个命令的并行等等。这时subprocess中的Popen命令就能有效的完成我们需要的操作 。
1
2
3
4
5
|
>>>
import
subprocess
>>>command_line
=
raw_input
()
ping
-
c
10
www.baidu.com
>>>args
=
shlex.split(command_line)
>>>p
=
subprocess.Popen(args)
|
利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe)
1
2
3
4
5
|
import
subprocess
child1
=
subprocess.Popen([
"ls"
,
"-l"
], stdout
=
subprocess.PIPE)
child2
=
subprocess.Popen([
"wc"
], stdin
=
child1.stdout,stdout
=
subprocess.PIPE)
out
=
child2.communicate()
print
(out)
|
communicate() 方法从stdout和stderr中读出数据,并输入到stdin中.
2、多进程(multiprocessing包) 。
(1)、multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程.
进程池 (Process Pool)可以创建多个进程.
apply_async(func,args) 从进程池中取出一个进程执行func,args为func的参数。它将返回一个AsyncResult的对象,你可以对该对象调用get()方法以获得结果.
close() 进程池不再创建新的进程 。
join() wait进程池中的全部进程。必须对Pool先调用close()方法才能join.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ == "tyomcat"
# "我的电脑有4个cpu"
from
multiprocessing
import
Pool
import
os, time
def
long_time_task(name):
print
'Run task %s (%s)...'
%
(name, os.getpid())
start
=
time.time()
time.sleep(
3
)
end
=
time.time()
print
'Task %s runs %0.2f seconds.'
%
(name, (end
-
start))
if
__name__
=
=
'__main__'
:
print
'Parent process %s.'
%
os.getpid()
p
=
Pool()
for
i
in
range
(
4
):
p.apply_async(long_time_task, args
=
(i,))
print
'Waiting for all subprocesses done...'
p.close()
p.join()
print
'All subprocesses done.'
|
(2)、多进程共享资源 。
通过共享内存和Manager对象:用一个进程作为服务器,建立Manager来真正存放资源.
其它的进程可以通过参数传递或者根据地址来访问Manager,建立连接后,操作服务器上的资源.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ == "tyomcat"
from
multiprocessing
import
Queue,Pool
import
multiprocessing,time,random
def
write(q):
for
value
in
[
'A'
,
'B'
,
'C'
,
'D'
]:
print
"Put %s to Queue!"
%
value
q.put(value)
time.sleep(random.random())
def
read(q,lock):
while
True
:
lock.acquire()
if
not
q.empty():
value
=
q.get(
True
)
print
"Get %s from Queue"
%
value
time.sleep(random.random())
else
:
break
lock.release()
if
__name__
=
=
"__main__"
:
manager
=
multiprocessing.Manager()
q
=
manager.Queue()
p
=
Pool()
lock
=
manager.Lock()
pw
=
p.apply_async(write,args
=
(q,))
pr
=
p.apply_async(read,args
=
(q,lock))
p.close()
p.join()
print
print
"所有数据都写入并且读完"
|
4、异步 。
无论是线程还是进程,使用的都是同步进制,当发生阻塞时,性能会大幅度降低,无法充分利用CPU潜力,浪费硬件投资,更重要造成软件模块的铁板化,紧耦合,无法切割,不利于日后扩展和变化.
不管是进程还是线程,每次阻塞、切换都需要陷入系统调用(system call),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪一个进程(线程)。多个线程之间在一些访问互斥的代码时还需要加上锁, 。
现下流行的异步server都是基于事件驱动的(如nginx).
异步事件驱动模型中,把会导致阻塞的操作转化为一个异步操作,主线程负责发起这个异步操作,并处理这个异步操作的结果。由于所有阻塞的操作都转化为异步操作,理论上主线程的大部分时间都是在处理实际的计算任务,少了多线程的调度时间,所以这种模型的性能通常会比较好.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
最后此篇关于python并发编程之多进程、多线程、异步和协程详解的文章就讲到这里了,如果你想了解更多关于python并发编程之多进程、多线程、异步和协程详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试打印 timeval 类型的值。实际上我可以打印它,但我收到以下警告: 该行有多个标记 格式“%ld”需要“long int”类型,但参数 2 的类型为“struct timeval” 程序
我正在编写自己的 unix 终端,但在执行命令时遇到问题: 首先,我获取用户输入并将其存储到缓冲区中,然后我将单词分开并将它们存储到我的 argv[] 数组中。IE命令是“firefox”以启动存储在
我是 CUDA 的新手。我有一个关于一个简单程序的问题,希望有人能注意到我的错误。 __global__ void ADD(float* A, float* B, float* C) { con
我有一个关于 C 语言 CGI 编程的一般性问题。 我使用嵌入式 Web 服务器来处理 Web 界面。为此,我在服务器中存储了一个 HTML 文件。在此 HTML 文件中包含 JavaScript 和
**摘要:**在代码的世界中,是存在很多艺术般的写法,这可能也是部分程序员追求编程这项事业的内在动力。 本文分享自华为云社区《【云驻共创】用4种代码中的艺术试图唤回你对编程的兴趣》,作者: break
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是让函数在调用它的级别创建变量。 createVariable testFunc() [1] "test" > testFunc2() [1]
以下代码用于将多个连续的空格替换为1个空格。虽然我设法做到了,但我对花括号的使用感到困惑。 这个实际上运行良好: #include #include int main() { int ch, la
我正在尝试将文件写入磁盘,然后自动重新编译。不幸的是,某事似乎不起作用,我收到一条我还不明白的错误消息(我是 C 初学者 :-)。如果我手动编译生成的 hello.c,一切正常吗?! #include
如何将指针值传递给结构数组; 例如,在 txt 上我有这个: John Doe;xxxx@hotmail.com;214425532; 我的代码: typedef struct Person{
我尝试编写一些代码来检索 objectID,结果是 2B-06-01-04-01-82-31-01-03-01-01 . 这个值不正确吗? // Send a SysObjectId SNMP req
您好,提前感谢您的帮助, (请注意评论部分以获得更多见解:即,以下示例中的成本列已添加到此问题中;西蒙提供了一个很好的答案,但成本列本身并未出现在他的数据响应中,尽管他提供的功能与成本列一起使用) 我
我想知道是否有人能够提出一些解决非线性优化问题的软件包的方法,而非线性优化问题可以为优化解决方案提供整数变量?问题是使具有相等约束的函数最小化,该函数受某些上下边界约束的约束。 我已经在R中使用了'n
我是 R 编程的初学者,正在尝试向具有 50 列的矩阵添加一个额外的列。这个新列将是该行中前 10 个值的平均值。 randomMatrix <- generateMatrix(1,5000,100,
我在《K&R II C 编程 ANSI C》一书中读到,“>>”和“0; nwords--) sum += *buf++; sum = (sum >>
当下拉列表的选择发生变化时,我想: 1) 通过 div 在整个网站上显示一些 GUI 阻止覆盖 2)然后处理一些代码 3) 然后隐藏叠加层。 问题是,当我在事件监听器函数中编写此逻辑时,将执行 onC
我正在使用 Clojure 和 RESTEasy 设计 JAX-RS REST 服务器. 据我了解,用 Lisp 系列语言编写的应用程序比用“传统”命令式语言编写的应用程序更多地构建为“特定于领域的语
我目前正在研究一种替代出勤监控系统作为一项举措。目前,我设计的用户表单如下所示: Time Stamp Userform 它的工作原理如下: 员工将选择他/她将使用的时间戳类型:开始时间、超时、第一次
我是一名学生,试图自学编程,从在线资源和像您这样的人那里获得帮助。我在网上找到了一个练习来创建一个小程序来执行此操作: 编写一个程序,读取数字 a 和 b(长整型)并列出 a 和 b 之间有多少个数字
我正在尝试编写一个 shell 程序,给定一个参数,打印程序的名称和参数中的每个奇数词(即,不是偶数词)。但是,我没有得到预期的结果。在跟踪我的程序时,我注意到,尽管奇数词(例如,第 5 个词,5 %
只是想知道是否有任何 Java API 可以让您控制台式机/笔记本电脑外壳上的 LED? 或者,如果不可能,是否有可能? 最佳答案 如果你说的是前面的 LED 指示电源状态和 HDD 繁忙状态,恐怕没
我是一名优秀的程序员,十分优秀!