python 线程,进程与协程
引言
在学习过socket和socketserver后,我们了解到socketserver可以支持IO多路复用。在定义socketserver服务端的时候一般会使用:
server = socketserver.ThreadingTCPServer(settings.IP_PORT, MyServer)
ThreadingTCPServer这个类便是可以支持多线程和TCP协议的socketserver模块。读源码的时候可以发现其继承关系:
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
右边的TCPServer实际上是它主要的功能父类,而左边的ThreadingMixIn则是实现了多线程的类,它自己本身则没有任何代码。MixIn在python的类命名中,很常见,一般被称为“混入”,戏称“乱入”,通常为了某种重要功能被子类继承。
class ThreadingMixIn: daemon_threads = False def process_request_thread(self, request, client_address):
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request) def process_request(self, request, client_address): t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()
一、线程:
import threading
import time def show(arg):
time.sleep(1)
print('thread'+str(arg)) for i in range(10):
t = threading.Thread(target=show, args=(i,))
t.start() print('main thread stop')
import threading
class MyThread(threading.Thread):
def __init__(self,func,args):
self.func = func
self.args = args
super(MyThread,self).__init__() #继承父类构造方法
def run(self):
self.func(self.args)
def f2(arg):
print(arg)
obj = MyThread(f2,123)
obj.start()
自定义线程类
#!/usr/bin/env python
# _*_ coding:utf_8 _*_
import threading
import time
NUM = 0
def f1():
global NUM
NUM+=1
name = t.getName()
time.sleep(1)
print(name,'执行结果',NUM)
for i in range(10):
t = threading.Thread(target=f1)
t.start()
#f1作为子线程执行,由于存在time.sleep(1),当主进程执行完毕之后,子线程才开始执行。导致结果出错。
print('执行结束')
执行结果:
执行结束
Thread-1 执行结果 10
Thread-4 执行结果 10
Thread-3 执行结果 10
Thread-5 执行结果 10
Thread-2 执行结果 10
Thread-6 执行结果 10
Thread-8 执行结果 10
Thread-7 执行结果 10
Thread-10 执行结果 10
Thread-9 执行结果 10
- Lock 普通锁(不可嵌套)
- RLock 普通锁(可嵌套)常用
- Semaphore 信号量
- event 事件
- condition 条件
import threading
import time
NUM = 0
def f1(i,lock):
global NUM
name = t.getName()#t是定义的线程,将这句代码放在线程锁之后会导致无法获取正确的线程名
lock.acquire() #定义锁作用空间的起始位置
NUM+=1
#name = threading.current_thread().name #等效于getName,不过输出的是每次执行的线程名
time.sleep(1)
print(name,i,'执行结果',NUM)
lock.release() #释放锁
lock = threading.RLock()
#lock = threading.Lock() for i in range(30):
t = threading.Thread(target=f1,args=(i,lock,))
t.start()
#f1作为子线程执行,由于存在time.sleep(1),当主进程执行完毕之后,子线程才开始执行。如果不使用线程锁的话结果出错。
print('执行结束')
线程锁
import threading
import time
NUM = 0
def f1(i,lock):
global NUM
name = t.getName()
lock.acquire() #定义锁作用空间的起始位置
NUM+=1
name = t.getName()
time.sleep(1)
print(name,i,'执行结果',NUM)
lock.release() #释放锁
lock = threading.BoundedSemaphore(5)
for i in range(30):
t = threading.Thread(target=f1,args=(i,lock,))
t.start() print('执行结束')
信号量
import threading
def func(e,i):
print(i)
e.wait() #检测当前event是什么状态,如果是红灯,则阻塞,绿灯则放行。默认为红灯。
print(i+100)
event = threading.Event()
for i in range(10):
t = threading.Thread(target=func,args=(event,i))
t.start()
event.clear() #将状态设置为红灯。
inp = input('>>> ')
if inp.strip() =='b':
event.set() #将状态设置为绿灯
事件
import threading
def condiction():
ret = False
inp = input('>>> ')
if inp == 'y':
ret = True
return ret
def func(cond,i):
print(i)
cond.acquire()
cond.wait_for(condiction)
#接受函数condition的返回值,Wait until a condition evaluates to True
print(i+100)
cond.release()
c=threading.Condition()
for i in range(10):
t = threading.Thread(target=func,args=(c,i))
t.start()
条件锁1
上面的例子每次只会释放一个线程。
import threading
def run(n):
con.acquire()
con.wait() #Wait until notified or until a timeout occurs
print('run this threading %s'%n)
con.release()
if __name__ == '__main__':
con= threading.Condition()
for i in range(10):
t = threading.Thread(target=run,args=(i,))
t.start()
while True:
inp = input('>>> ')
if inp =='q':
break
con.acquire()
con.notify(int(inp))
#根据条件唤醒一个到多个线程,如果线程之前没有处于acquire的Lock状态,则报错
#RuntimeError: cannot notify on un-acquired lock
con.release()
条件锁2
from threading import Timer
def hello():
print('hello')
t=Timer(1,hello) #延迟1s后执行
t.start()
定时器
既然介绍了多线程和线程锁,那就不得不提及python的GIL,也就是全局解释器锁。在编程语言的世界,python因为GIL的问题广受诟病,因为它在解释器的层面限制了程序在同一时间只有一个线程被CPU实际执行,而不管你的程序里实际开了多少条线程。所以我们经常能发现,python中的多线程编程有时候效率还不如单线程,就是因为这个原因。那么,对于这个GIL,一些普遍的问题如下:
每种编程语言都有GIL吗?
以python官方Cpython解释器为代表....其他语言好像未见。
为什么要有GIL?
作为解释型语言,Python的解释器必须做到既安全又高效。我们都知道多线程编程会遇到的问题。解释器要留意的是避免在不同的线程操作内部共享的数据。同时它还要保证在管理用户线程时总是有最大化的计算资源。那么,不同线程同时访问时,数据的保护机制是怎样的呢?答案是解释器全局锁GIL。GIL对诸如当前线程状态和为垃圾回收而用的堆分配对象这样的东西的访问提供着保护。
为什么不能去掉GIL?
首先,在早期的python解释器依赖较多的全局状态,传承下来,使得想要移除当今的GIL变得更加困难。其次,对于程序员而言,仅仅是想要理解它的实现就需要对操作系统设计、多线程编程、C语言、解释器设计和CPython解释器的实现有着非常彻底的理解。
在1999年,针对Python1.5,一个“freethreading”补丁已经尝试移除GIL,用细粒度的锁来代替。然而,GIL的移除给单线程程序的执行速度带来了一定的负面影响。当用单线程执行时,速度大约降低了40%。虽然使用两个线程时在速度上得到了提高,但这个提高并没有随着核数的增加而线性增长。因此这个补丁没有被采纳。
另外,在python的不同解释器实现中,如PyPy就移除了GIL,其执行速度更快(不单单是去除GIL的原因)。然而,我们通常使用的CPython占有着统治地位的使用量,所以,你懂的。
在Python 3.2中实现了一个新的GIL,并且带着一些积极的结果。这是自1992年以来,GIL的一次最主要改变。旧的GIL通过对Python指令进行计数来确定何时放弃GIL。在新的GIL实现中,用一个固定的超时时间来指示当前的线程以放弃这个锁。在当前线程保持这个锁,且当第二个线程请求这个锁的时候,当前线程就会在5ms后被强制释放掉这个锁(这就是说,当前线程每5ms就要检查其是否需要释放这个锁)。当任务是可行的时候,这会使得线程间的切换更加可预测。GIL对我们有什么影响?
最大的影响是我们不能随意使用多线程。要区分任务场景。
在单核cpu情况下对性能的影响可以忽略不计,多线程多进程都差不多。在多核CPU时,多线程效率较低。GIL对单进程和多进程没有影响。在实际使用中有什么好的建议?
建议在IO密集型任务中使用多线程,在计算密集型任务中使用多进程。深入研究python的协程机制,你会有惊喜的。
- queue.Queue :先进先出队列
- queue.LifoQueue :后进先出队列
- queue.PriorityQueue :优先级队列
- queue.deque :双向队列
import queue
q = queue.Queue(5)#定义最大元素个数
q.put(11)
q.put(22)
q.put(33)
print(q.get())
print(q.get())
print(q.get())
Queue
maxsize 队列的最大元素个数,也就是
queue.Queue(5)
中的5。当队列内的元素达到这个值时,后来的元素默认会阻塞,等待队列腾出位置。def __init__(self, maxsize=0):self.maxsize = maxsize
self._init(maxsize)- qsize() 获取当前队列中元素的个数,也就是队列的大小
- empty() 判断当前队列是否为空,返回True或者False
- full() 判断当前队列是否已满,返回True或者False
put(self, block=True, timeout=None)
往队列里放一个元素,默认是阻塞和无时间限制的。如果,block设置为False,则不阻塞,这时,如果队列是满的,放不进去,就会弹出异常。如果timeout设置为n秒,则会等待这个秒数后才put,如果put不进去则弹出异常。
- get(self, block=True, timeout=None)
从队列里获取一个元素。参数和put是一样的意思。 join() 阻塞进程,直到所有任务完成,需要配合另一个方法task_done。
def join(self):with self.all_tasks_done:
while self.unfinished_tasks:
self.all_tasks_done.wait()task_done() 表示某个任务完成。每一条get语句后需要一条task_done。
import queue
q = queue.Queue(5)
q.put(11)
q.put(22)
print(q.get())
q.task_done()
print(q.get())
q.task_done()
q.join()
import queue
q = queue.LifoQueue()
q.put(123)
q.put(456)
print(q.get())
LifoQueue
q = queue.PriorityQueue()
q.put((1,"zhang1"))
q.put((1,"zhang2"))
q.put((1,"zhang3"))
q.put((3,"zhang3"))
print(q.get())
PriorityQueue
q = queue.deque()
q.append(11)
q.append(22) q.appendleft(33)
q.appendleft(44)
print(q.popleft())
print(q.popleft())
print(q.pop())
print(q.pop())
q.append(55)
deque
生产者消费者模型
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
#!/use/bin/env python
#_*_ coding:utf_8 _*_
import time
import queue
import threading
q = queue.Queue(10)
def productor(i):
while True:
q.put('开工,生产%s个'%i)
time.sleep(1) def consumer(k):
while True:
print('%s,消费%s'%(q.get(),k))
time.sleep(2) for i in range(3):
t= threading.Thread(target=productor,args=(i,))
t.start() for k in range(10):
v = threading.Thread(target=consumer,args=(k,))
v.start()
线程池
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import queue
import threading
import time class ThreadPool:
def __init__(self, maxsize=5):
self.maxsize = maxsize
self._q = queue.Queue(maxsize)
for i in range(maxsize):
self._q.put(threading.Thread)
# 【threading.Thread,threading.Thread,threading.Thread,threading.Thread,threading.Thread】得到线程类
def get_thread(self):
return self._q.get() def add_thread(self):
self._q.put(threading.Thread) pool = ThreadPool(5) def task(arg,p):
print(arg)
#print(threading.current_thread())
print(threading.currentThread()) #源码中写道currentThread = current_thread,这两个命令效果是一样的。
time.sleep(1) p.add_thread() #在方法执行完之后将新线程加入线程池 for i in range(100): t = pool.get_thread()# threading.Thread类
obj = t(target=task,args=(i,pool,))
obj.start()
线程池1.0
这是个比较low的线程池,预先开辟5个线程空间,不考虑实际环境,而且使用过的线程并没有被回收,看一下执行结果便清楚了。
0
<Thread(Thread-1, started 5600)>
1
<Thread(Thread-2, started 5752)>
2
<Thread(Thread-3, started 4460)>
3
<Thread(Thread-4, started 2692)>
4
<Thread(Thread-5, started 2424)>
5
<Thread(Thread-6, started 4628)>
6
<Thread(Thread-7, started 5532)>
7
<Thread(Thread-8, started 4084)>
8
<Thread(Thread-9, started 4472)>
9
<Thread(Thread-10, started 6024)>
10
<Thread(Thread-11, started 1580)>
11
<Thread(Thread-12, started 1960)>
12
<Thread(Thread-13, started 1148)>
13
<Thread(Thread-14, started 4908)>
14
<Thread(Thread-15, started 4468)>
15
<Thread(Thread-16, started 1660)>
16
<Thread(Thread-17, started 5200)>
17
<Thread(Thread-18, started 6108)>
18
<Thread(Thread-19, started 3648)>
19
<Thread(Thread-20, started 3740)>
20
<Thread(Thread-21, started 2628)>
21
<Thread(Thread-22, started 3752)>
#提前中断,原循环为100个
线程池1.0执行结果
下面是武sir提供的一个较好的线程池
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
import queue
import threading
import contextlib
import time StopEvent = object() #设置终止符,可以为None class ThreadPool(object): def __init__(self, max_num, max_task_num = None):
if max_task_num:
self.q = queue.Queue(max_task_num) #max_task_num指定可以接收到的任务
else:
self.q = queue.Queue()
self.max_num = max_num
self.cancel = False
self.terminal = False
self.generate_list = [] #当前创建的线程
self.free_list = [] #当前空闲的线程 def run(self, func, args, callback=None):
"""
线程池执行一个任务
:param func: 任务函数
:param args: 任务函数所需参数
:param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
:return: 如果线程池已经终止,则返回True否则None
"""
if self.cancel:
return
if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: #判断创建线程的条件,没有空线程并且当前线程小于要执行的任务总数。
self.generate_thread()
w = (func, args, callback,) #将参数放在元组中,把元组当做整体的任务放在队列中
self.q.put(w) def generate_thread(self):
"""
创建一个线程
"""
t = threading.Thread(target=self.call)
t.start() def call(self):
"""
循环去获取任务函数并执行任务函数
"""
current_thread = threading.currentThread
self.generate_list.append(current_thread) event = self.q.get() #取任务
while event != StopEvent: func, arguments, callback = event
try:
result = func(*arguments)
success = True
except Exception as e:
success = False
result = None if callback is not None:
try:
callback(success, result)
except Exception as e:
pass with self.worker_state(self.free_list, current_thread): #执行完action后判断当前任务状态。
if self.terminal:
event = StopEvent #没有任务后赋予控制,释放线程
else:
event = self.q.get() #取新任务
else: self.generate_list.remove(current_thread) def close(self):
"""
执行完所有的任务后,所有线程停止
"""
self.cancel = True
full_size = len(self.generate_list)
while full_size:
self.q.put(StopEvent)
full_size -= 1 def terminate(self):
"""
无论是否还有任务,终止线程
"""
self.terminal = True while self.generate_list:
self.q.put(StopEvent) self.q.empty() @contextlib.contextmanager
def worker_state(self, state_list, worker_thread):
"""
用于记录线程中正在等待的线程数
"""
state_list.append(worker_thread)
try:
yield
finally:
state_list.remove(worker_thread) pool = ThreadPool(5) def callback(status, result):
# status, execute action status
# result, execute action return value
pass def action(i):
print(i) for i in range(300):
ret = pool.run(action, (i,), callback) # time.sleep(5)
# print(len(pool.generate_list), len(pool.free_list))
# print(len(pool.generate_list), len(pool.free_list))
线程池2.0
进程
python的multiprocess模块提供了Process类,实现进程相关的功能。
由于它是基于fork机制的,因此不被windows平台支持。想要在windows中运行,必须使用if __name__ == '__main__:
的方式,显然这只能用于调试和学习,不能用于实际环境。
下面是一个简单的多进程例子,可以发现Process的用法和Thread的用法几乎一模一样。
from multiprocessing import Process def foo(i):
print("This is Process ", i) if __name__ == '__main__':
for i in range(5):
p = Process(target=foo, args=(i,))
p.start()
进程的数据共享
每个进程都有自己独立的数据空间,不同进程之间通常是不能共享数据,创建一个进程需要非常大的开销。
from multiprocessing import Process
list_1 = []
def foo(i):
list_1.append(i)
print("This is Process ", i," and list_1 is ", list_1) if __name__ == '__main__':
for i in range(5):
p = Process(target=foo, args=(i,))
p.start() print("The end of list_1:", list_1)
运行上面的代码,可以发现列表list_1在各个进程中只有自己的数据,完全无法共享。
想要进程之间进行资源共享可以使用queues/Array/Manager这三个multiprocess模块提供的类。
使用Array共享数据
from multiprocessing import Process
from multiprocessing import Array def Foo(i,temp):
temp[0] += 100
for item in temp:
print(i,'----->',item) if __name__ == '__main__':
temp = Array('i', [11, 22, 33, 44])
for i in range(2):
p = Process(target=Foo, args=(i,temp))
p.start()
对于Array数组类,括号内的“i”表示它内部的元素全部是int类型,而不是指字符i,列表内的元素可以预先指定,也可以指定列表长度。概括的来说就是Array类在实例化的时候就必须指定数组的数据类型和数组的大小,类似temp = Array('i', 5)
。对于数据类型有下面的表格对应:
'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
使用Manager共享数据
from multiprocessing import Process,Manager def Foo(i,dic):
dic[i] = 100+i
print(dic.values()) if __name__ == '__main__':
manage = Manager()
dic = manage.dict()
for i in range(10):
p = Process(target=Foo, args=(i,dic))
p.start()
p.join()
Manager比Array要好用一点,因为它可以同时保存多种类型的数据格式。
使用queues的Queue类共享数据
import multiprocessing
from multiprocessing import Process
from multiprocessing import queues def foo(i,arg):
arg.put(i)
print('The Process is ', i, "and the queue's size is ", arg.qsize()) if __name__ == "__main__":
li = queues.Queue(20, ctx=multiprocessing)
for i in range(10):
p = Process(target=foo, args=(i,li,))
p.start()
这里就有点类似上面的队列了。但是会产生脏数据
既然涉及到进程间资源共享,进程之间肯定会有脏数据的产生,在进程中也设置了进程锁,和线程锁的使用方法一样:
from multiprocessing import Process
from multiprocessing import queues
from multiprocessing import Array
from multiprocessing import RLock, Lock, Event, Condition, Semaphore
import multiprocessing
import time def foo(i,lis,lc):
lc.acquire()
lis[0] = lis[0] - 1
time.sleep(1)
print('say hi',lis[0])
lc.release() if __name__ == "__main__":
# li = []
li = Array('i', 1)
li[0] = 10
lock = RLock()
for i in range(10):
p = Process(target=foo,args=(i,li,lock))
p.start()
进程锁
同样的,进程也有进程池的概念,不过python中提供了进程池,只需from multiprocessing import Pool
即可
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Pool
import time def f1(args):
time.sleep(1)
print(args) if __name__ == '__main__':
p = Pool(5)
for i in range(30):
p.apply_async(func=f1, args= (i,))
p.close() # 等子进程执行完毕后关闭进程池
# time.sleep(2)
# p.terminate() # 立刻关闭进程池
p.join()
进程池
进程池内部维护一个进程序列,当使用时,去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有以下几个主要方法:
apply:从进程池里取一个进程并执行
apply_async:apply的异步版本
terminate:立刻关闭进程池
join:主进程等待所有子进程执行完毕。必须在close或terminate之后。
close:等待所有进程结束后,才关闭进程池。
ps:IO密集型操作用线程,CPU密集型操作用进程,协程也适合处理IO密集型操作。
协程
线程和进程的操作是由程序触发系统接口,最后的执行者是系统。而协程的操作则是程序员指定的,人为的实现并发处理。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时。协程,则只使用一个线程,分解一个线程成为多个“微线程”,在一个线程中规定某个代码块的执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO)。
有第三方模块为我们提供了协程,在使用它们之前,需要先安装。这里介绍一下greenlet和gevent。本质上,gevent是对greenlet的高级封装,因此一般用它就行,这是一个相当高效的模块。
3.1 greenlet
from greenlet import greenlet def test1():
print(12)
gr2.switch()
print(34)
gr2.switch() def test2():
print(56)
gr1.switch()
print(78) gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
greenlet
实际上,greenlet就是通过switch方法在不同的任务之间进行切换。
3.2 gevent
from gevent import monkey; monkey.patch_all()
import gevent
import requests def f(url):
print('GET: %s' % url)
resp = requests.get(url)
data = resp.text
print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])
gevent
通过joinall将任务f和它的参数进行统一调度,实现单线程中的协程。代码封装层次很高,实际使用只需要了解它的几个主要方法即可。
python 线程,进程与协程的更多相关文章
- Python 线程&进程与协程
Python 的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承.Py ...
- 多任务-python实现-进程,协程,线程总结(2.1.16)
@ 目录 1.类比 2.总结 关于作者 1.类比 一个生产玩具的工厂: 一个生产线成为一个进程,一个生产线有多个工人,所以工人为线程 单进程-多线程:一条生产线,多个工人 多进程-多线程:多条生产线, ...
- Python之线程、进程和协程
python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...
- python成长之路 :线程、进程和协程
python线程 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分 ...
- Python之路【第七篇】:线程、进程和协程
Python之路[第七篇]:线程.进程和协程 Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 1 ...
- python运维开发(十一)----线程、进程、协程
内容目录: 线程 基本使用 线程锁 自定义线程池 进程 基本使用 进程锁 进程数据共享 进程池 协程 线程 线程使用的两种方式,一种为我们直接调用thread模块上的方法,另一种我们自定义方式 方式一 ...
- Python 线程和进程和协程总结
Python 线程和进程和协程总结 线程和进程和协程 进程 进程是程序执行时的一个实例,是担当分配系统资源(CPU时间.内存等)的基本单位: 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其 ...
- python 线程 进程 协程 学习
转载自大神博客:http://www.cnblogs.com/aylin/p/5601969.html 仅供学习使用···· python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和 ...
- python并发编程之Queue线程、进程、协程通信(五)
单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...
- Python菜鸟之路:Python基础-线程、进程、协程
上节内容,简单的介绍了线程和进程,并且介绍了Python中的GIL机制.本节详细介绍线程.进程以及协程的概念及实现. 线程 基本使用 方法1: 创建一个threading.Thread对象,在它的初始 ...
随机推荐
- IPC机制总结
IPC机制: 1. 多进程概念: 2. 序列化机制和Binder: 3. 进程间通信:Bundle.文件共享.AIDL.Messenger.ContentProvider.Socket: 操作系统的设 ...
- 3 August
P1013 进制位 结论:加法必为 \(n-1\) 进制:\({(n-1)}^1\) 位必为数字 1:\(0+0=0\). 模拟.字符串. #include <cstdio> #inclu ...
- U-Boot是什么
U-Boot U-Boot,全称 Universal Boot Loader,是遵循GPL条款的开放源码项目.U-Boot的作用是系统引导.U-Boot从FADSROM.8xxROM.PPCBOOT逐 ...
- 左手Mongodb右手Redis 第一章,进入Mongodb和Redis的世界
---恢复内容开始--- 1,为什么要使用非关系型数据库,关系型数据库咋滴,不能用嘛? 存在即合理,非关系型数据库的出现,那说明关系型数据库不适用了. 非关系型数据库(NOSQL)-->Not ...
- bzoj 1026: [SCOI2009]windy数 & 数位DP算法笔记
数位DP入门题之一 也是我所做的第一道数位DP题目 (其实很久以前就遇到过 感觉实现太难没写) 数位DP题目貌似多半是问从L到R内有多少个数满足某些限制条件 只要出题人不刻意去卡多一个$log$什么的 ...
- 用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 构建 RESTful Flask API 定义资源路由 格式 ...
- flysql 里两种传参的方式
传参的方式,两个标清楚: for lists_bx_goods in out_list: sql = XDO().get_update_sql('init_goods_test', { "一 ...
- mysqldump导出数据出现问题
利用mysqldump导出数据时提示warning,A partial dump from a server that has GTIDsubt@ubt-All-Series:~$ mysqldum ...
- SSDT and Shadow SSDT table
参考:http://x86.renejeschke.de/html/file_module_x86_id_313.html http://msdn.microsoft.com/en-us/librar ...
- cabal替代脚本
由于网络原因,直接使用cabal update不成功,只能自己写脚本直接从网上拖包下来,自己安装. 但是这样做的缺点是需要手动处理dependency,当然,也可以把脚本写的复杂些,自动来处理depe ...