0 intro
1.1 网络编程
1.2 fileIO流和文件处理
1.3 云计算
2 并发处理concurrency
3 容错处理
4 hdfs
5 hdfs usage api
6.0 存储
6.1 dynamo
6.2 bigtable
6.3 cassandra
MapReduce
作业
第一次作业
略
第二次作业
选择多线程还是多进程
在这个问题上,首先要看下你的程序是属于哪种类型的。一般分为两种 CPU 密集型 和 I/O 密集型。
- CPU 密集型:程序比较偏重于计算,需要经常使用 CPU 来运算。例如科学计算的程序,机器学习的程序等。
- I/O 密集型:顾名思义就是程序需要频繁进行输入输出操作。爬虫程序就是典型的 I/O 密集型程序。
如果程序是属于 CPU 密集型,建议使用多进程。而多线程就更适合应用于 I/O 密集型程序。
题一
(1)
不使用spark所说的哈夫曼编码压缩,原因是:
采用哈夫曼编码的方式进行文件的压缩和解压缩主要原理是通过huffman编码来表示字符,出现次数多的编码短,出现次数少的编码长,这样整体而言,所需的总的bit位是减少的。但是当大部分字符出现的频率都差不多时,huffman压缩的压缩率就会很低。
老师要求的频率都是256,不合适。
最后采用暴力的双重循环生成数据。。。
改用Python,结果生成数据的时间为:
(2)
多线程读取同一个文件,要求不能重复,不能遗漏。
(3)
Python多线程写同一个文件
1 通过队列Queue来实现。
采用线程优先级队列( Queue)进行写入
主线程启动一个线程来读文件,把文件的内容放到队列里。
然后启动若干线程,全部从队列取数据。python中的Queue是线程安全的。
http://stackoverflow.com/questions/18781354/is-iterating-over-a-python-file-object-thread-safe
Is iterating over a Python file object thread safe?
在这里Queue作为资源池,线程去从资源池中取数据进行处理,可是为什么需要用到Queue呢, 因为可能资源池很大,而开的线程数有限,所以等一个线程处理完它的任务之后,它可以继续去取资源处理!这就可以让先执行完一个任务的线程不立即停下来,而是去取另一个资源处理,直到没有数据的时候它才会停下来。简单理解:q.task_done是表明当前的资源处理完了,q.join()会等到所有的资源都被处理了才会向下继续执行,这就是一种同步。
参考原文链接:https://blog.csdn.net/xiao_huocai/article/details/74781820
队列线程的思想: 首先创建一个全局共享的队列,队列中只存在有限个元素,并将所有的数据逐条加入到队列中,并调用队列的join函数进行等待。之后便可以开启若干线程,线程的任务就是不断的从队列中取数据进行处理就可以了。
2.线程同步
使用Thread对象的Lock和Rlock可以实现简单的线程同步.这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间
2 通过linecache来实现。linecache可以指定行号来读取一个文件的任意一行。主线程先分配给每个读线程各自读取的行号,然后各线程根据行号用linecache来读取。
此种方法依赖于linecache读取任意一行的速度,如果是大文件,则比较慢。
比如线程1需要读取10-20行。假设线程1有自己的文件指针的话,读了地10行,可以直接很快定位到第11行。但是用linecache读取的话,每一次读取一行就没有什么关系了。当然,对于linecache怎么定位到任意一行,其中的原理我也没探究过。
3分文件读取。python先调用linux命令head和tail,将一个文件分成若干个文件。然后每个读线程负责读取一个文件即可。
python 多线程
多线程 + 队列
Queue用于建立和操作队列,常和threading类一起用来建立一个简单的线程队列。
Queue.Queue(maxsize) FIFO(先进先出队列)
Queue.LifoQueue(maxsize) LIFO(先进后出队列)
Queue.PriorityQueue(maxsize) 为优先级越高的越先出来,对于一个队列中的所有元素组成的entries,优先队列优先返回的一个元素是sorted(list(entries))[0]。至于对于一般的数据,优先队列取什么东西作为优先度要素进行判断,官方文档给出的建议是一个tuple如(priority, data),取priority作为优先度。
如果设置的maxsize小于1,则表示队列的长度无限长
FIFO队列
FIFO是常用的队列,常用的方法有:
Queue.qsize() 返回队列大小
Queue.empty() 判断队列是否为空
Queue.full() 判断队列是否满了
Queue.get([block[,timeout]]) 从队列头删除并返回一个item,block默认为True,表示当队列为空却去get的时候会阻塞线程,等待直到有有item出现为止来get出这个item。如果是False的话表明当队列为空你却去get的时候,会引发异常。
在block为True的情况下可以再设置timeout参数。表示当队列为空,get阻塞timeout指定的秒数之后还没有get到的话就引发Full异常。
Queue.put(…[,block[,timeout]]) 向队尾插入一个item,同样若block=True的话队列满时就阻塞等待有空位出来再put,block=False时引发异常。
同get的timeout,put的timeout是在block为True的时候进行超时设置的参数。
Queue.task_done() 从场景上来说,处理完一个get出来的item之后,调用task_done将向队列发出一个信号,表示本任务已经完成。
Queue.join() 监视所有item并阻塞主线程,直到所有item都调用了task_done之后主线程才继续向下执行。这么做的好处在于,假如一个线程开始处理最后一个任务,它从任务队列中拿走最后一个任务,此时任务队列就空了但最后那个线程还没处理完。当调用了join之后,主线程就不会因为队列空了而擅自结束,而是等待最后那个线程处理完成了。
作业二
producer.java写完了
多线程的写入的三种方法
1.线程同步
为了处理这种共享资源竞争,可以使用同步机制。所谓同步机制,指的是两个线程同时作用在一个对象上,应该保持对象数据的统一性和整体性。Java 提供 synchronized 关键字,为防止资源冲突提供了内置支持。共享资源一般是文件、输入/输出端口或打印机
第一题 法一
IO写入方法:Reader、PrintWriter(PrintWriter这个很好用,在写数据的同事可以格式化)
线程数:时间
1 : 103040
2 : 98338
4 : 115989
8 : 129334
16 : 128296
32 : 128153
第一题 法二
IO写入方法:BufferedOutputStream
线程数:时间
1 : 110837
2 : 99897
4 : 105910
8 : 94820
16 : 90362
32 : 102011
第一题 法三
OutputStream
奇慢无比,劝退
这是32线程的
改用dataOutputStream,速度正常多了,这是32线程的
如果第一题写入byte[]而不是int的话,速度慢而且输出不正常,所以还是用int!
32线程的时间:两倍长,大小还更大。。。2.8G左右
重新开了一下电脑所用时间不一样,时间差了1w左右。。。 |