python 线程:
Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。
1 #!/usr/bin/env python
2 #_*_ coding:utf-8 _*_
3 import threading
4 import time
5
6 def show(arg):
7 time.sleep(1)
8 print('threading' + str(arg))
9
10 for i in range(10):
11 t = threading.Thread(target=show, args=(i,))
12 t.start()
13
14 print ('main thread stop!')
上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
更多方法:
- start 线程准备就绪,等待CPU调度。
- setName 为线程设置名称。
- getName 获取线程名称。
- setDaemon 设置为后台线程或前台线程(默认)。
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止。
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后等待前台线程也执行完成后,程序停止。
- join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得没有意义。
- run 线程被cpu调度后自动执行线程对象的run方法。
线程锁
由于线程之间是进行随机调度,并且每个线程可能只执行n条之后,CPU接着执行其它线程,所以,可能出现如下问题:
#!/usr/bin/env python
#_*_coding:utf-8_*_
import threading
import time
gl_num = 0
def show(arg):
global gl_num
time.sleep(1)
gl_num += 1
print gl_num
for i in range(10):
t = threading.Thread(target=show, args=(i,))
t.start()
print 'main thread stop!'
未使用锁
1 #!/usr/bin/env python
2 #_*_coding:utf-8_*_
3
4 import threading
5 import time
6
7 gl_num = 0
8
9 lock = threading.Rlock()
10
11 def Func():
12 lock.acquire()
13 global gl_num
14 gl_num += 1
15 time.sleep(1)
16 print gl_num
17 lock.release()
18
19 for i in range(10):
20 t = threading.Thread(target=Func)
21 t.start()
event
python线程的事件用于主线程控制其它线程的执行,事件主要提供了三个方法set,wait,clear.
事件处理的机制:全局定义了一个“Flag”,如果“Falg”值为False,那么当程序执行event.wait方法时就会阻塞,如果“Falg”值为True,那么执行event.wait方法时便不再阻塞。
- clear: 将“Flag”设置为False
- set: 将“Flag”设置为True
1 #!/usr/bin/env python
2 #_*_coding:utf-8_*_
3
4 import threading
5
6 def do(event):
7 print('start')
8 event.wait()
9 print('execute')
10
11 event_obj = threading.Event()
12 for i in range(10):
13 t = threading.Thread(target=do, args=(event_obj,))
14 t.start()
15
16 event_obj.clear()
17 inp = raw_input('input:')
18 if inp == 'true':
19 event_obj.set()
python 进程
1 from multiprocessing import Process
2 import threading
3 import time
4
5 def foo(i):
6 print ('Hello victor!', i)
7
8 for i in range(10):
9 p = Process(target=foo, args=(i,))
10 p.start()
注意:由于进程之间的数据需要各自持有一份,所以创建进程需要非常大的开销。
进程数据共享
进程各自持有一份数据,默认无法共享数据。
#!/usr/bin/env python
# _*_coding:utf-8_*_
from multiprocessing import Process
from multiprocessing import Manager
import time
li = []
def foo(i):
li.append(i)
print('Hello victor!', li)
for i in range(10):
p = Process(target=foo, args=(i,))
p.start()
print ('hehe', li)
进程间默认无法数据共享
1 # 方法一,Array
2 from multiprocessing import Process, Array
3 temp = Array('i', [1,2,3,4])
4
5 def Foo(i):
6 temp[i] = 10 + i
7 for i in temp:
8 print i, '------' ,item
9
10 for i in range(2):
11 p = Process(target=Foo, args=(i,))
12 p.start()
13
14
15 # 方法二: manage.dict()共享数据
16 from multiprocessing import Process, Manager
17
18 manage = Manage()
19 dic = manage.dict()
20
21 def Foo(i):
22 dic[i] = 10 + i
23 print dic.values()
24
25 for i in range(2):
26 p = Process(target=Foo, args=(i,))
27 p.start()
28 p.join()
'c': ctypes.c_char, 'u': ctypes.c_wchar,
'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
'h': ctypes.c_short, 'H': ctypes.c_ushort,
'i': ctypes.c_int, 'I': ctypes.c_uint,
'l': ctypes.c_long, 'L': ctypes.c_ulong,
'f': ctypes.c_float, 'd': ctypes.c_double
类型对应表
当创建进程时(非使用时),共享数据会被拿到子进程中,当进程中执行完毕后,再赋值给原值。
#!/usr/bin/env python
# _*_coding:utf-8_*_
from multiprocessing import Process, Array, RLock
def Foo(lock, temp, i):
'''
将第0个数加100
'''
lock.acquire()
temp[0] = 100 + i
for item in temp:
print (i, '-----', item)
lock.release()
lock = RLock()
temp = Array('i', [11,22,33,44])
for i in range(20):
p = Process(target=Foo,args=(lock, temp, i, ))
p.start()
进程锁实例
进程池
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
- apply
- apply_async
1 #!/usr/bin/env python
2 # _*_coding:utf-8_*_
3 from multiprocessing import Process, Pool
4 import time
5
6 def Foo(i):
7 time.sleep(2)
8 return i + 100
9
10 def Bar(arg):
11 print (arg)
12
13 pool = Pool(5)
14 #print pool.apply(Foo,(1,))
15 #print pool.apply.async(func = Foo, args=(1,)).get()
16
17 for i in range(10):
18 pool.apply_async(func=Foo, args=(i,), callback=Bar)
19
20 print ('end')
21 pool.close()
22 pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
协程
线程和进程的操作是由程序触发系统接口,最后的执行者是系统,协程的操作则是程序员。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
协程的使用场景:当程序中存在大量不需要CPU的操作时(IO操作),适合协程。
greenlet
1 #!/usr/bin/env python
2 # _*_coding:utf-8_*_
3
4 from greenlet import greenlet
5
6 def test1():
7 print 1
8 gr2.switch()
9 print 2
10 gr2.switch()
11
12 def test2():
13 print 3
14 gr1.switch()
15 print 4
16
17 gr1 = greenlet(test1)
18 gr2 = greenlet(test2)
19 gr1.switch()
gevent
1 import gevent
2
3 def foo():
4 print ('Running in foo...')
5 gevent.sleep(0)
6 print ('Explicit context switch to foo again...')
7
8 def bar():
9 print ('Explicit context to bar...')
10 gevent.sleep(0)
11 print ('Implicit context switch back to bar...')
12
13 gevent,joinall([
14 gevent.spawn(foo),
15 gevent.spawn(bar),
16 ])
遇到IO自动切换:
from gevent import monkey
from gevent import monkey.patch_all()
import gevent
import urllib2
def f(url):
print ('GET: %s ' % url)
resp = urllib2.urlopen(url)
data = resp.read()
print ('%d bytes received from %s.' % (len(data), url))
gevent.join([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])
View Code
转载于:https://www.cnblogs.com/victorfeng/p/5527479.html