Python 爬虫进阶六之多进程的用法

python 中的多线程其实并不是真正的多线程,并不能做到充分利用多核 CPU 资源。 如果想要充分利用,在 python 中大部分情况需要使用多进程,那么这个包就叫做 multiprocessing。 借助它,可以轻松完成从单进程到并发执行的转换。multiprocessing 支持子进程、通信和共享数据、执行不同形式的同步,提供了 Process、Queue、Pipe、Lock 等组件。 那么本节要介绍的内容有:

  • Process
  • Lock
  • Semaphore
  • Queue
  • Pipe
  • Pool

Process

基本使用

在 multiprocessing 中,每一个进程都用一个 Process 类来表示。首先看下它的 API

Process([group [, target [, name [, args [, kwargs]]]]])
  • target 表示调用对象,你可以传入方法的名字
  • args 表示被调用对象的位置参数元组,比如 target 是函数 a,他有两个参数 m,n,那么 args 就传入 (m, n) 即可
  • kwargs 表示调用对象的字典
  • name 是别名,相当于给这个进程取一个名字
  • group 分组,实际上不使用

我们先用一个实例来感受一下:

import multiprocessingdef process(num):print 'Process:', numif __name__ == '__main__':for i in range(5):p = multiprocessing.Process(target=process, args=(i,))p.start()

最简单的创建 Process 的过程如上所示,target 传入函数名,args 是函数的参数,是元组的形式,如果只有一个参数,那就是长度为 1 的元组。 然后调用 start () 方法即可启动多个进程了。 另外你还可以通过 cpu_count () 方法还有 active_children () 方法获取当前机器的 CPU 核心数量以及得到目前所有的运行的进程。 通过一个实例来感受一下:

import multiprocessing
import timedef process(num):time.sleep(num)print 'Process:', numif __name__ == '__main__':for i in range(5):p = multiprocessing.Process(target=process, args=(i,))p.start()print('CPU number:' + str(multiprocessing.cpu_count()))for p in multiprocessing.active_children():print('Child process name: ' + p.name + ' id: ' + str(p.pid))print('Process Ended')

运行结果:

Process: 0
CPU number:8
Child process name: Process-2 id: 9641
Child process name: Process-4 id: 9643
Child process name: Process-5 id: 9644
Child process name: Process-3 id: 9642
Process Ended
Process: 1
Process: 2
Process: 3
Process: 4

自定义类

另外你还可以继承 Process 类,自定义进程类,实现 run 方法即可。 用一个实例来感受一下:

from multiprocessing import Process
import timeclass MyProcess(Process):def __init__(self, loop):Process.__init__(self)self.loop = loopdef run(self):for count in range(self.loop):time.sleep(1)print('Pid: ' + str(self.pid) + ' LoopCount: ' + str(count))if __name__ == '__main__':for i in range(2, 5):p = MyProcess(i)p.start()

在上面的例子中,我们继承了 Process 这个类,然后实现了 run 方法。打印出来了进程号和参数。 运行结果:

Pid: 28116 LoopCount: 0
Pid: 28117 LoopCount: 0
Pid: 28118 LoopCount: 0
Pid: 28116 LoopCount: 1
Pid: 28117 LoopCount: 1
Pid: 28118 LoopCount: 1
Pid: 28117 LoopCount: 2
Pid: 28118 LoopCount: 2
Pid: 28118 LoopCount: 3

可以看到,三个进程分别打印出了 2、3、4 条结果。 我们可以把一些方法独立的写在每个类里封装好,等用的时候直接初始化一个类运行即可。

deamon

在这里介绍一个属性,叫做 deamon。每个线程都可以单独设置它的属性,如果设置为 True,当父进程结束后,子进程会自动被终止。 用一个实例来感受一下,还是原来的例子,增加了 deamon 属性:

from multiprocessing import Process
import timeclass MyProcess(Process):def __init__(self, loop):Process.__init__(self)self.loop = loopdef run(self):for count in range(self.loop):time.sleep(1)print('Pid: ' + str(self.pid) + ' LoopCount: ' + str(count))if __name__ == '__main__':for i in range(2, 5):p = MyProcess(i)p.daemon = Truep.start()print 'Main process Ended!'

在这里,调用的时候增加了设置 deamon,最后的主进程(即父进程)打印输出了一句话。 运行结果:

Main process Ended!

结果很简单,因为主进程没有做任何事情,直接输出一句话结束,所以在这时也直接终止了子进程的运行。 这样可以有效防止无控制地生成子进程。如果这样写了,你在关闭这个主程序运行时,就无需额外担心子进程有没有被关闭了。 不过这样并不是我们想要达到的效果呀,能不能让所有子进程都执行完了然后再结束呢?那当然是可以的,只需要加入 join () 方法即可。

from multiprocessing import Process
import timeclass MyProcess(Process):def __init__(self, loop):Process.__init__(self)self.loop = loopdef run(self):for count in range(self.loop):time.sleep(1)print('Pid: ' + str(self.pid) + ' LoopCount: ' + str(count))if __name__ == '__main__':for i in range(2, 5):p = MyProcess(i)p.daemon = Truep.start()p.join()print 'Main process Ended!'

在这里,每个子进程都调用了 join () 方法,这样父进程(主进程)就会等待子进程执行完毕。 运行结果:

Pid: 29902 LoopCount: 0
Pid: 29902 LoopCount: 1
Pid: 29905 LoopCount: 0
Pid: 29905 LoopCount: 1
Pid: 29905 LoopCount: 2
Pid: 29912 LoopCount: 0
Pid: 29912 LoopCount: 1
Pid: 29912 LoopCount: 2
Pid: 29912 LoopCount: 3
Main process Ended!

发现所有子进程都执行完毕之后,父进程最后打印出了结束的结果。

Lock

在上面的一些小实例中,你可能会遇到如下的运行结果:
在这里插入图片描述
什么问题?有的输出错位了。这是由于并行导致的,两个进程同时进行了输出,结果第一个进程的换行没有来得及输出,第二个进程就输出了结果。所以导致这种排版的问题。 那这归根结底是因为线程同时资源(输出操作)而导致的。 那怎么来避免这种问题?那自然是在某一时间,只能一个进程输出,其他进程等待。等刚才那个进程输出完毕之后,另一个进程再进行输出。这种现象就叫做 “互斥”。 我们可以通过 Lock 来实现,在一个进程输出时,加锁,其他进程等待。等此进程执行结束后,释放锁,其他进程可以进行输出。 我们现用一个实例来感受一下:

from multiprocessing import Process, Lock
import timeclass MyProcess(Process):def __init__(self, loop, lock):Process.__init__(self)self.loop = loopself.lock = lockdef run(self):for count in range(self.loop):time.sleep(0.1)#self.lock.acquire()print('Pid: ' + str(self.pid) + ' LoopCount: ' + str(count))#self.lock.release()if __name__ == '__main__':lock = Lock()for i in range(10, 15):p = MyProcess(i, lock)p.start()

首先看一下不加锁的输出结果:


```python
Pid: 45755 LoopCount: 0
Pid: 45756 LoopCount: 0
Pid: 45757 LoopCount: 0
Pid: 45758 LoopCount: 0
Pid: 45759 LoopCount: 0
Pid: 45755 LoopCount: 1
Pid: 45756 LoopCount: 1
Pid: 45757 LoopCount: 1
Pid: 45758 LoopCount: 1
Pid: 45759 LoopCount: 1
Pid: 45755 LoopCount: 2Pid: 45756 LoopCount: 2Pid: 45757 LoopCount: 2
Pid: 45758 LoopCount: 2
Pid: 45759 LoopCount: 2
Pid: 45756 LoopCount: 3
Pid: 45755 LoopCount: 3
Pid: 45757 LoopCount: 3
Pid: 45758 LoopCount: 3
Pid: 45759 LoopCount: 3
Pid: 45755 LoopCount: 4
Pid: 45756 LoopCount: 4
Pid: 45757 LoopCount: 4
Pid: 45759 LoopCount: 4
Pid: 45758 LoopCount: 4
Pid: 45756 LoopCount: 5
Pid: 45755 LoopCount: 5
Pid: 45757 LoopCount: 5
Pid: 45759 LoopCount: 5
Pid: 45758 LoopCount: 5
Pid: 45756 LoopCount: 6Pid: 45755 LoopCount: 6Pid: 45757 LoopCount: 6
Pid: 45759 LoopCount: 6
Pid: 45758 LoopCount: 6
Pid: 45755 LoopCount: 7Pid: 45756 LoopCount: 7Pid: 45757 LoopCount: 7
Pid: 45758 LoopCount: 7
Pid: 45759 LoopCount: 7
Pid: 45756 LoopCount: 8Pid: 45755 LoopCount: 8Pid: 45757 LoopCount: 8
Pid: 45758 LoopCount: 8Pid: 45759 LoopCount: 8Pid: 45755 LoopCount: 9
Pid: 45756 LoopCount: 9
Pid: 45757 LoopCount: 9
Pid: 45758 LoopCount: 9
Pid: 45759 LoopCount: 9
Pid: 45756 LoopCount: 10
Pid: 45757 LoopCount: 10
Pid: 45758 LoopCount: 10
Pid: 45759 LoopCount: 10
Pid: 45757 LoopCount: 11
Pid: 45758 LoopCount: 11
Pid: 45759 LoopCount: 11
Pid: 45758 LoopCount: 12
Pid: 45759 LoopCount: 12
Pid: 45759 LoopCount: 13

可以看到有些输出已经造成了影响。 然后我们对其加锁:```python
from multiprocessing import Process, Lock
import timeclass MyProcess(Process):def __init__(self, loop, lock):Process.__init__(self)self.loop = loopself.lock = lockdef run(self):for count in range(self.loop):time.sleep(0.1)self.lock.acquire()print('Pid: ' + str(self.pid) + ' LoopCount: ' + str(count))self.lock.release()if __name__ == '__main__':lock = Lock()for i in range(10, 15):p = MyProcess(i, lock)p.start()

我们在 print 方法的前后分别添加了获得锁和释放锁的操作。这样就能保证在同一时间只有一个 print 操作。 看一下运行结果:

Pid: 45889 LoopCount: 0
Pid: 45890 LoopCount: 0
Pid: 45891 LoopCount: 0
Pid: 45892 LoopCount: 0
Pid: 45893 LoopCount: 0
Pid: 45889 LoopCount: 1
Pid: 45890 LoopCount: 1
Pid: 45891 LoopCount: 1
Pid: 45892 LoopCount: 1
Pid: 45893 LoopCount: 1
Pid: 45889 LoopCount: 2
Pid: 45890 LoopCount: 2
Pid: 45891 LoopCount: 2
Pid: 45892 LoopCount: 2
Pid: 45893 LoopCount: 2
Pid: 45889 LoopCount: 3
Pid: 45890 LoopCount: 3
Pid: 45891 LoopCount: 3
Pid: 45892 LoopCount: 3
Pid: 45893 LoopCount: 3
Pid: 45889 LoopCount: 4
Pid: 45890 LoopCount: 4
Pid: 45891 LoopCount: 4
Pid: 45892 LoopCount: 4
Pid: 45893 LoopCount: 4
Pid: 45889 LoopCount: 5
Pid: 45890 LoopCount: 5
Pid: 45891 LoopCount: 5
Pid: 45892 LoopCount: 5
Pid: 45893 LoopCount: 5
Pid: 45889 LoopCount: 6
Pid: 45890 LoopCount: 6
Pid: 45891 LoopCount: 6
Pid: 45893 LoopCount: 6
Pid: 45892 LoopCount: 6
Pid: 45889 LoopCount: 7
Pid: 45890 LoopCount: 7
Pid: 45891 LoopCount: 7
Pid: 45892 LoopCount: 7
Pid: 45893 LoopCount: 7
Pid: 45889 LoopCount: 8
Pid: 45890 LoopCount: 8
Pid: 45891 LoopCount: 8
Pid: 45892 LoopCount: 8
Pid: 45893 LoopCount: 8
Pid: 45889 LoopCount: 9
Pid: 45890 LoopCount: 9
Pid: 45891 LoopCount: 9
Pid: 45892 LoopCount: 9
Pid: 45893 LoopCount: 9
Pid: 45890 LoopCount: 10
Pid: 45891 LoopCount: 10
Pid: 45892 LoopCount: 10
Pid: 45893 LoopCount: 10
Pid: 45891 LoopCount: 11
Pid: 45892 LoopCount: 11
Pid: 45893 LoopCount: 11
Pid: 45893 LoopCount: 12
Pid: 45892 LoopCount: 12
Pid: 45893 LoopCount: 13

嗯,一切都没问题了。 所以在访问临界资源时,使用 Lock 就可以避免进程同时占用资源而导致的一些问题。

Semaphore

信号量,是在进程同步过程中一个比较重要的角色。可以控制临界资源的数量,保证各个进程之间的互斥和同步。 如果你学过操作系统,那么一定对这方面非常了解,如果你还不了解信号量是什么,可以参考 信号量解析 来了解一下它是做什么的。 那么接下来我们就用一个实例来演示一下进程之间利用 Semaphore 做到同步和互斥,以及控制临界资源数量。

from multiprocessing import Process, Semaphore, Lock, Queue
import timebuffer = Queue(10)
empty = Semaphore(2)
full = Semaphore(0)
lock = Lock()class Consumer(Process):def run(self):global buffer, empty, full, lockwhile True:full.acquire()lock.acquire()buffer.get()print('Consumer pop an element')time.sleep(1)lock.release()empty.release()class Producer(Process):def run(self):global buffer, empty, full, lockwhile True:empty.acquire()lock.acquire()buffer.put(1)print('Producer append an element')time.sleep(1)lock.release()full.release()if __name__ == '__main__':p = Producer()c = Consumer()p.daemon = c.daemon = Truep.start()c.start()p.join()c.join()print 'Ended!'

如上代码实现了注明的生产者和消费者问题,定义了两个进程类,一个是消费者,一个是生产者。 定义了一个共享队列,利用了 Queue 数据结构,然后定义了两个信号量,一个代表缓冲区空余数,一个表示缓冲区占用数。 生产者 Producer 使用 empty.acquire () 方法来占用一个缓冲区位置,然后缓冲区空闲区大小减小 1,接下来进行加锁,对缓冲区进行操作。然后释放锁,然后让代表占用的缓冲区位置数量 + 1,消费者则相反。 运行结果如下:

Producer append an element
Producer append an element
Consumer pop an element
Consumer pop an element
Producer append an element
Producer append an element
Consumer pop an element
Consumer pop an element
Producer append an element
Producer append an element
Consumer pop an element
Consumer pop an element
Producer append an element
Producer append an element

可以发现两个进程在交替运行,生产者先放入缓冲区物品,然后消费者取出,不停地进行循环。 通过上面的例子来体会一下信号量的用法。

Queue

在上面的例子中我们使用了 Queue,可以作为进程通信的共享队列使用。 在上面的程序中,如果你把 Queue 换成普通的 list,是完全起不到效果的。即使在一个进程中改变了这个 list,在另一个进程也不能获取到它的状态。 因此进程间的通信,队列需要用 Queue。当然这里的队列指的是 multiprocessing.Queue 依然是用上面那个例子,我们一个进程向队列中放入数据,然后另一个进程取出数据。

from multiprocessing import Process, Semaphore, Lock, Queue
import time
from random import randombuffer = Queue(10)
empty = Semaphore(2)
full = Semaphore(0)
lock = Lock()class Consumer(Process):def run(self):global buffer, empty, full, lockwhile True:full.acquire()lock.acquire()print 'Consumer get', buffer.get()time.sleep(1)lock.release()empty.release()class Producer(Process):def run(self):global buffer, empty, full, lockwhile True:empty.acquire()lock.acquire()num = random()print 'Producer put ', numbuffer.put(num)time.sleep(1)lock.release()full.release()if __name__ == '__main__':p = Producer()c = Consumer()p.daemon = c.daemon = Truep.start()c.start()p.join()c.join()print 'Ended!'

运行结果:

Producer put  0.719213647437
Producer put  0.44287326683
Consumer get 0.719213647437
Consumer get 0.44287326683
Producer put  0.722859424381
Producer put  0.525321338921
Consumer get 0.722859424381
Consumer get 0.525321338921

可以看到生产者放入队列中数据,然后消费者将数据取出来。 get 方法有两个参数,blocked 和 timeout,意思为阻塞和超时时间。默认 blocked 是 true,即阻塞式。 当一个队列为空的时候如果再用 get 取则会阻塞,所以这时候就需要吧 blocked 设置为 false,即非阻塞式,实际上它就会调用 get_nowait () 方法,此时还需要设置一个超时时间,在这么长的时间内还没有取到队列元素,那就抛出 Queue.Empty 异常。 当一个队列为满的时候如果再用 put 放则会阻塞,所以这时候就需要吧 blocked 设置为 false,即非阻塞式,实际上它就会调用 put_nowait () 方法,此时还需要设置一个超时时间,在这么长的时间内还没有放进去元素,那就抛出 Queue.Full 异常。 另外队列中常用的方法 Queue.qsize () 返回队列的大小 ,不过在 Mac OS 上没法运行。 原因:

def qsize(self): # Raises NotImplementedError on Mac OSX because of broken sem_getvalue() return self._maxsize - self._sem._semlock._get_value()

Queue.empty () 如果队列为空,返回 True, 反之 False Queue.full () 如果队列满了,返回 True, 反之 False Queue.get ([block [, timeout]]) 获取队列,timeout 等待时间 Queue.get_nowait () 相当 Queue.get (False) Queue.put (item) 阻塞式写入队列,timeout 等待时间 Queue.put_nowait (item) 相当 Queue.put (item, False)

Pipe

管道,顾名思义,一端发一端收。 Pipe 可以是单向 (half-duplex),也可以是双向 (duplex)。我们通过 mutiprocessing.Pipe (duplex=False) 创建单向管道 (默认为双向)。一个进程从 PIPE 一端输入对象,然后被 PIPE 另一端的进程接收,单向管道只允许管道一端的进程输入,而双向管道则允许从两端输入。 用一个实例来感受一下:

from multiprocessing import Process, Pipeclass Consumer(Process):def __init__(self, pipe):Process.__init__(self)self.pipe = pipedef run(self):self.pipe.send('Consumer Words')print 'Consumer Received:', self.pipe.recv()class Producer(Process):def __init__(self, pipe):Process.__init__(self)self.pipe = pipedef run(self):print 'Producer Received:', self.pipe.recv()self.pipe.send('Producer Words')if __name__ == '__main__':pipe = Pipe()p = Producer(pipe[0])c = Consumer(pipe[1])p.daemon = c.daemon = Truep.start()c.start()p.join()c.join()print 'Ended!'

在这里声明了一个默认为双向的管道,然后将管道的两端分别传给两个进程。两个进程互相收发。观察一下结果:

Producer Received: Consumer Words
Consumer Received: Producer Words
Ended!

以上是对 pipe 的简单介绍。

Pool

在利用 Python 进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用 multiprocessing 中的 Process 动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。 Pool 可以提供指定数量的进程,供用户调用,当有新的请求提交到 pool 中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。 在这里需要了解阻塞和非阻塞的概念。 阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。 阻塞即要等到回调结果出来,在有结果之前,当前进程会被挂起。 Pool 的用法有阻塞和非阻塞两种方式。非阻塞即为添加进程后,不一定非要等到改进程执行完就添加其他进程运行,阻塞则相反。 现用一个实例感受一下非阻塞的用法:

from multiprocessing import Lock, Pool
import timedef function(index):print 'Start process: ', indextime.sleep(3)print 'End process', indexif __name__ == '__main__':pool = Pool(processes=3)for i in xrange(4):pool.apply_async(function, (i,))print "Started processes"pool.close()pool.join()print "Subprocess done."

在这里利用了 apply_async 方法,即非阻塞。 运行结果:

Started processes
Start process: Start process:  0 
1
Start process:  2
End processEnd process 0 
1
Start process:  3
End process 2
End process 3
Subprocess done.

可以发现在这里添加三个进程进去后,立马就开始执行,不用非要等到某个进程结束后再添加新的进程进去。 下面再看看阻塞的用法:

from multiprocessing import Lock, Pool
import timedef function(index):print 'Start process: ', indextime.sleep(3)print 'End process', indexif __name__ == '__main__':pool = Pool(processes=3)for i in xrange(4):pool.apply(function, (i,))print "Started processes"pool.close()pool.join()print "Subprocess done."

在这里只需要把 apply_async 改成 apply 即可。 运行结果如下:

Start process:  0
End process 0
Start process:  1
End process 1
Start process:  2
End process 2
Start process:  3
End process 3
Started processes
Subprocess done.

这样一来就好理解了吧? 下面对函数进行解释: apply_async (func [, args [, kwds [, callback]]]) 它是非阻塞,apply (func [, args [, kwds]]) 是阻塞的。 close () 关闭 pool,使其不在接受新的任务。 terminate () 结束工作进程,不在处理未完成的任务。 join () 主进程阻塞,等待子进程的退出, join 方法要在 close 或 terminate 之后使用。 当然每个进程可以在各自的方法返回一个结果。apply 或 apply_async 方法可以拿到这个结果并进一步进行处理。

from multiprocessing import Lock, Pool
import timedef function(index):print 'Start process: ', indextime.sleep(3)print 'End process', indexreturn indexif __name__ == '__main__':pool = Pool(processes=3)for i in xrange(4):result = pool.apply_async(function, (i,))print result.get()print "Started processes"pool.close()pool.join()print "Subprocess done."

运行结果:

Start process:  0
End process 0
0
Start process:  1
End process 1
1
Start process:  2
End process 2
2
Start process:  3
End process 3
3
Started processes
Subprocess done.

另外还有一个非常好用的 map 方法。 如果你现在有一堆数据要处理,每一项都需要经过一个方法来处理,那么 map 非常适合。 比如现在你有一个数组,包含了所有的 URL,而现在已经有了一个方法用来抓取每个 URL 内容并解析,那么可以直接在 map 的第一个参数传入方法名,第二个参数传入 URL 数组。 现在我们用一个实例来感受一下:

from multiprocessing import Pool
import requests
from requests.exceptions import ConnectionErrordef scrape(url):try:print requests.get(url)except ConnectionError:print 'Error Occured ', urlfinally:print 'URL ', url, ' Scraped'if __name__ == '__main__':pool = Pool(processes=3)urls = ['https://www.baidu.com','http://www.meituan.com/','http://blog.csdn.net/','http://xxxyxxx.net']pool.map(scrape, urls)

在这里初始化一个 Pool,指定进程数为 3,如果不指定,那么会自动根据 CPU 内核来分配进程数。 然后有一个链接列表,map 函数可以遍历每个 URL,然后对其分别执行 scrape 方法。 运行结果:

<Response [403]>
URL  http://blog.csdn.net/  Scraped
<Response [200]>
URL  https://www.baidu.com  Scraped
Error Occured  http://xxxyxxx.net
URL  http://xxxyxxx.net  Scraped
<Response [200]>
URL  http://www.meituan.com/  Scraped

可以看到遍历就这么轻松地实现了。

参考

https://docs.python.org/2/library/multiprocessing.html http://www.cnblogs.com/vamei/archive/2012/10/12/2721484.html http://www.cnblogs.com/kaituorensheng/p/4445418.html https://my.oschina.net/yangyanxing/blog/296052

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问&#xff0c;并发的访问会导致竞态&#xff0c;即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linux 并发相关基础概念 a -- 并发&#xff08;concurrency&#…

第三章:多坐标系

第一节&#xff1a;为什么要有多坐标系 当我们使用一个坐标系来描绘整个场景的时候&#xff0c;场景中的任意点都可以用该坐标系描述&#xff0c;此时如果有一只羊一遍摇动着耳朵&#xff0c;一边走&#xff0c;这个时候如果进行坐标的转换会发现异常的麻烦&#xff0c;此时如果…

Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

关与设备树的概念&#xff0c;我们在Exynos4412 内核移植&#xff08;六&#xff09;—— 设备树解析 里面已经学习过&#xff0c;下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构&#xff0c;设备树源(Device Tree Source)文件&#xff08;以…

Android 网络通信框架Volley简介(Google IO 2013)

1. 什么是Volley 在这之前&#xff0c;我们在程序中需要和网络通信的时候&#xff0c;大体使用的东西莫过于AsyncTaskLoader&#xff0c;HttpURLConnection&#xff0c;AsyncTask&#xff0c;HTTPClient&#xff08;Apache&#xff09;等&#xff0c;今年的Google I/O 2013上&…

Linux 设备驱动开发 —— platform设备驱动应用实例解析

前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 &#xff0c;下面将通过一个实例来深入我们的学习。 一、platform 驱动的工作过程 platform模型驱动编程&#xff0c;需要实现platform_device(设备)与platform_driver&#xff08;驱动&am…

Python爬虫入门四urllib库的高级用法

1.设置headers 有些网站不会同意程序直接用上面的方式进行访问&#xff0c;如果识别有问题&#xff0c;那么站点根本不会响应&#xff0c;所以为了完全模拟浏览器的工作&#xff0c;我们需要设置一些 Headers 的属性。 首先&#xff0c;打开我们的浏览器&#xff0c;调试浏览器…

进程上下文、中断上下文及原子上下文

谈论进程上下文 、中断上下文 、 原子上下文之前&#xff0c;有必要讨论下两个概念&#xff1a; a -- 上下文 上下文是从英文context翻译过来&#xff0c;指的是一种环境。相对于进程而言&#xff0c;就是进程执行时的环境&#xff1b; 具体来说就是各个变量和数据&#xff0c;…

Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

提到 sysfs 文件系统 &#xff0c;必须先需要了解的是Linux设备模型&#xff0c;什么是Linux设备模型呢&#xff1f; 一、Linux 设备模型 1、设备模型概述 从2.6版本开始&#xff0c;Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有独立的数据结构用来让内…

Python爬虫入门七正则表达式

已经搞定了怎样获取页面的内容&#xff0c;不过还差一步&#xff0c;这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢&#xff1f;下面就开始介绍一个十分强大的工具&#xff0c;正则表达式 1.了解正则表达式 正则表达式是用来匹配字符串非常强大的工具&#xff0c;在其…

Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统

一、什么是Linux设备文件系统 首先我们不看定义&#xff0c;定义总是太抽象很难理解&#xff0c;我们先看现象。当我们往开发板上移植了一个新的文件系统之后&#xff08;假如各种设备驱动也移植好了&#xff09;&#xff0c;启动开发板&#xff0c;我们用串口工具进入开发板&a…

情人节,教大家使用css画出一朵玫瑰花。

情人节到了&#xff0c;给大家来一朵高端的玫瑰花。 在网上看到的一个canvas实现的玫瑰花&#xff0c;效果很好&#xff0c;但是代码被压缩过&#xff0c;也没有注释&#xff0c;看的云里雾里的。 今天我教大脚用CSS来实现一朵玫瑰花。 先看效果 首先我们画出一个花瓣 1、画出一…

Linux 字符设备驱动开发基础(六)—— VFS 虚拟文件系统解析

一、VFS 虚拟文件系统基础概念 Linux 允许众多不同的文件系统共存&#xff0c;并支持跨文件系统的文件操作&#xff0c;这是因为有虚拟文件系统的存在。虚拟文件系统&#xff0c;即VFS&#xff08;Virtual File System&#xff09;是 Linux 内核中的一个软件抽象层。它通过一些…

vim使用—实现程序的自动补齐(C语言)

使用过Source Insight的人一定对它的自动补全功能印象深刻&#xff0c;在很多的集成开发环境中&#xff0c;也都支持自动补全。vim做为一个出色的编辑器&#xff0c;这样的功能当然少不了。至于如何实现程序自动补全&#xff0c;网上教程很多。这里&#xff0c;我将自己配置过程…

[C#]Attribute特性(3)——AttributeUsage特性和特性标识符

相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外&#xff0c;您可以用AttributeUsage特性来定义您想怎样使用这些特性。AttributeUsage特性采用如下的调用惯例&#xff1a; 1 [Attri…

Linux 命令 ——less命令

less 工具也是对文件或其它输出进行分页显示的工具&#xff0c;应该说是linux正统查看文件内容的工具&#xff0c;功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候&#xff0c;我们并没有办法向前面翻&#xff0c; 只能往后面看&#xff0c;但若使用了 less …

android闹钟实现原理

闹钟的原理可用下面我自己画的一幅图来概括&#xff1a;&#xff08;不对的地方&#xff0c;尽管吐槽&#xff09; 我们来看看新建闹钟到闹钟响铃的步骤&#xff1a; 1、新建一个闹钟&#xff1a; ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22…

将openstack的Token认证信息存储在memcache中

公司线上的openstack环境运行了5个多月的时间&#xff0c;keystone库的token表已经增长到了31GB&#xff0c;这个数据量还是很大的&#xff0c;对于以后的数据库备份很不方便。每次管理openstack的时候&#xff0c;都会产生一个新的token验证&#xff0c;而历史token信息其实都…

Linux 下shell编程

什么是shell?Shell是一个命令解析器&#xff0c;是介于Linux操作系统的内核(kernel)与用户之间的一个绝缘层。shell脚本就是讲各类命令预先放入其中&#xff0c;方便一次性执行的一个程序文件&#xff0c;主要用于方便管理员进行设置或者管理。 序员的角度来看&#xff0c; Sh…

linux 目录/sys 解析

今天学习Linux目录时&#xff0c;遇到/sys这个目录&#xff0c;老师怎么讲的&#xff0c;不太清楚&#xff0c;先对/sys目录知识进行一个整理 首先&#xff0c;对 /sys目录下的各个子目录进行具体说明&#xff1a; /sys下的子目录 内容 /sys/devices 该目录下…

南下事业篇——深圳 深圳(回顾)

2019独角兽企业重金招聘Python工程师标准>>> 二0一二年三月二十三号记录了下面的一篇日志&#xff0c;现在回味一下觉得自己有点惭愧&#xff0c;但不后悔&#xff0c;知道的越多就越了解自己的无知&#xff0c;工作之后渐渐磨灭了许多锐气&#xff0c;变得平滑低调…