网上看到一道题。https://github.com/Skinney/WordSorter
简单的描述就是,对一个已知的文本文件按行字符串自然序进行排序,结果输出到另一个文件。
设计了一系列算法。
先搞一个最简单的。
Allen01_SimpleSort
1 读取数据。
2 排序。
3 写回。
4 单线程完成所有任务。
数据都是字符串,可以使用桶排先预排序一下。
Allen02_String_Bucket
桶排。按照每一行字符串的前2个字符分为26*26个桶。
数据读取和数据入桶线程分开。
写文件线程必须等待数据入桶线程完成任务。并且对桶内数据进行排序。
面向字符串处理。
字符串处理太慢,改为字节处理。
Allen04_Bytes_Bucket
桶排。
数据读取和数据入桶线程分开。
写文件线程必须等待数据入桶线程完成任务。并且对桶内数据进行排序。
面向字节处理。
数据先按照数据块入一个中间queue,入桶线程解析数据块为多个字节数组,入桶。
桶内的数据排序过程可以并行化。
Allen05_Fixed_Sorter
桶排。
数据读取和数据入桶线程分开。
一组桶内排序线程按照桶的数量对桶内数据排序工作做固定划分。
写文件线程必须等待排序线程完成任务。
面向字节处理。
线程桶内数据排序的划分,由于是固定的,有可能导致线程的工作负载不同。
Allen06_Dynamic_Sorter
桶排。
数据读取和数据入桶线程分开。
一组桶内排序线程按照本身排序工作的进度竞争得到下一个需要排序的桶。
写文件线程必须等待排序线程完成任务。
面向字节处理。
这个方案还搞了一个变种,使用26*26*27的桶,效果不太好。
一个桶内数据排序完成,数据就可以写出了,单独有一个线程监控桶内数据排序情况,排好序了就尽量写出。
Allen08_Concurrent_Writer
桶排。
数据读取和数据入桶线程分开。
一组桶内排序线程按照本身排序工作的进度竞争得到下一个需要排序的桶。
写文件线程和排序线程并发运行。
面向字节处理。
写文件线程和排序线程通过queue通信。
原始的桶内数据使用java自带的ArrayList保存,感觉有点重量级。
自己实现了一个简单的list,来保持桶内数据。自行管理数组容量,动态扩展。
/**
* 简单列表,代替ArrayList。
* */
public class AllenSimpleList implements AllenList {
private int capacity = 16;
private byte[][] datas = new byte[capacity][];
private int next = 0;
public void addData(byte[] data) {
if (next != capacity) {
datas[next++] = data;
} else {
int new_capacity = capacity << 1;
byte[][] new_datas = new byte[new_capacity][];
System.arraycopy(datas, 0, new_datas, 0, capacity);
new_datas[next++] = data;
capacity = new_capacity;
datas = new_datas;
}
}
public int getLength() {
return next;
}
public void mergeOtherList(AllenSimpleList other) {
if (capacity < next + other.next) {
int new_capacity = next + other.next;
byte[][] new_datas = new byte[new_capacity][];
System.arraycopy(datas, 0, new_datas, 0, next);
System.arraycopy(other.datas, 0, new_datas, next, other.next);
capacity = new_capacity;
datas = new_datas;
next = capacity;
} else {
System.arraycopy(other.datas, 0, datas, next, other.next);
next += other.next;
}
}
public void sort() {
AllenSorter.sort(datas, 0, next);
}
public void write(OutputStream out) throws Exception {
for (int i = 0; i < next; i++) {
out.write(datas[i]);
}
}
@Override
public void addData(int threadIndex, byte[] data) {
addData(data);
}
同时,原有排序线程和写出线程使用queue通信,可以配置为忙查询。
Allen08_Concurrent_Writer_Need_Strategy
使用了AllenSimpleList。
需要一个Strategy来控制程序。Strategy可以控制
是否设置线程的优先级。
使用何种策略进行排序线程和写文件线程的通信,queue还是轮询.
写文件线程是否会Yield。
数据入桶也可以并行化。
有可能导致桶内数据并发修改时不一致。
第1个方案,每一个线程一个单独的数据桶。
/**
* 多个simpleList,按照线程号分流。
* */
public class AllenSafeSimpleList implements AllenList {
private AllenSimpleList[] list;
public AllenSafeSimpleList(int threadCount) {
list = new AllenSimpleList[threadCount];
for (int i = 0; i < list.length; i++) {
list[i] = new AllenSimpleList();
}
}
public void addData(int threadIndex, byte[] data) {
list[threadIndex].addData(data);
}
@Override
public void sort() {
for (int i = 1; i < list.length; i++) {
if (list[i].getLength() > 0) {
list[0].mergeOtherList(list[i]);
}
}
list[0].sort();
}
@Override
public void write(OutputStream out) throws Exception {
list[0].write(out);
}
}
第2个方案,主备方案。
/**
* 2个simpleList,主备分流。
* */
public class AllenSafeSimpleList2 implements AllenList {
private AllenSimpleList mainList;
private AllenSimpleList bakList;
private AtomicBoolean main = new AtomicBoolean(false);
private AtomicBoolean bak = new AtomicBoolean(false);
public AllenSafeSimpleList2() {
mainList = new AllenSimpleList();
bakList = new AllenSimpleList();
}
public void addData(int threadIndex, byte[] data) {
if (main.compareAndSet(false, true)) {
mainList.addData(data);
main.set(false);
return;
} else {
while (bak.compareAndSet(false, true)) {
bakList.addData(data);
bak.set(false);
return;
}
}
}
@Override
public void sort() {
if (bakList.getLength() != 0) {
mainList.mergeOtherList(bakList);
}
mainList.sort();
}
@Override
public void write(OutputStream out) throws Exception {
mainList.write(out);
}
}
Allen12_Concurrent_DataWorker_Need_Strategy
桶排。
数据读取和数据入桶线程分开。
一组桶内排序线程按照本身排序工作的进度竞争得到下一个需要排序的桶。
写文件线程和排序线程并发运行。
面向字节处理。
入桶线程变成多线程。
需要一个Strategy来控制程序。Strategy可以控制
是否设置线程的优先级。
使用何种策略进行排序线程和写文件线程的通信,queue还是轮询.
写文件线程是否会Yield。
使用AllenSafeSimpleList还是AllenSafeSimpleList2。
bug fix:
AllenSafeSimpleList2
@Override
public void addData(int threadIndex, byte[] data) {
if (main.compareAndSet(false, true)) {
mainList.addData(data);
main.set(false);
return;
} else {
while (true) {
if (bak.compareAndSet(false, true)) {
bakList.addData(data);
bak.set(false);
return;
}
}
}
}
分享到:
相关推荐
Java 对大数据量文件内容的多线程读取和排序 Java 对大数据量文件内容的多线程读取和排序是非常复杂的任务,涉及到多个方面的技术,包括文件读取、多线程处理、排序算法等。本文将对该问题进行详细的分析和解决方案...
Java 对大数据量文件内容的多线程读取和排序 在处理大数据量文件内容时,多线程读取和排序是非常重要的。下面我们将讨论如何使用 Java 对大数据量文件内容进行多线程读取和排序。 首先,我们需要生成一个随机的...
在这个案例中,我们使用的是CListCtrl,这是一个单文本内列表控件,它可以显示文件和目录的列表,并允许用户进行交互,如选择、排序和导航。 文件拷贝功能的实现涉及Windows API函数,如CopyFile或CopyFileEx。这些...
在本资源中,"多线程排序演示 VC源码" 提供了一个使用Microsoft Visual C++ (VC++)编写的示例,展示了如何利用多线程进行数据排序。这种技术在处理大量数据时尤其有用,因为它可以将排序工作分解到多个处理器核心上...
通过阅读和理解源码,我们可以根据实际需求进行定制和优化,比如增加多线程支持,提高排序性能,或者添加自定义比较函数来实现特定排序规则。 在实际应用中,文本数组排序模块可以用于各种情况。例如,在处理用户...
文本文件内容排序功能: 每行是一条记录,每行可以有多列,列间按预定义的分隔符分隔; 可以按单列或多列组合排序,每列的顺序可以设置为反序或者正序; 列的数据类型可以是字符串、整数、浮点数,比较排序时按指定...
【文本文件搜索工具】是一个基于Java Swing开发的应用程序,它专为用户提供了在特定文件夹内快速查找含有特定关键字的文本文件的能力。这个工具对于那些需要频繁在大量文本数据中定位信息的用户来说非常实用,比如...
为了解决这个问题,开发者们引入了多线程下载技术,通过同时发起多个下载请求,显著提升了文件下载速度。本文将深入探讨一个基于Winsock库实现的HTTP多线程下载程序,分析其工作原理以及如何进行子文件的下载与合并...
在实际应用中,可以结合并行化策略,如归并排序与多线程,进一步提升排序效率。 6. **内存管理**: 大文本处理可能会遇到内存限制问题。为解决此问题,可以使用流式处理(streaming)或外部排序(external sorting...
通常,这种文本文件会包含源码的注释、使用方法、注意事项等内容。如果要深入理解并运用这段源码,需要打开此文件查看具体实现和指导。 总的来说,这个易语言的示例程序为我们提供了一个在处理大型数据集合时如何...
在C#编程中,对照片进行按拍照日期排序并读取文本文件内容来自定义重命名是一项常见的任务,尤其在管理大量个人或专业照片时。这个过程涉及到文件系统操作、日期时间处理以及文本文件的读取。以下是实现这一功能所需...
总之,Android文件排序是一个综合性的任务,涉及到文件I/O、排序算法、用户界面设计等多个方面。通过合理利用`File`类和`Comparator`接口,我们可以实现灵活且高效的文件排序功能,提供良好的用户体验。
`_柧.TXT`:此文件名看起来可能是错误编码或者非标准字符,无法确定其具体内容,但可能是一个文本文件,包含了代码注释、设计思路或者其他开发相关的笔记。 `NUMBERS2`、`SRCHCRT`、`NUMCLASS`、`BACKPRNT`、`...
在C语言中,可以使用`pthread`库实现多线程编程。 6. **文件处理技巧**: - 使用`mmap()`函数可以将文件映射到内存空间,这样可以避免频繁的读写操作,提高效率。但是,这种方法对于超大文件仍需谨慎,因为它可能...
4. **说明.TXT** - 另一份可能包含项目详细说明的文本文件,可能包括每个示例的目的和实现细节。 5. **NUMBERS2**、**SRCHCRT**、**NUMCLASS**、**BACKPRNT**、**BUSYPRIO**、**BUSYWAIT** - 这些很可能是不同的源...
在Java编程中,处理大文件是一项挑战,特别...总结来说,Java大文件读取排序涉及了Java I/O,流处理,分块策略,排序算法,多线程技术,以及可能的第三方库和工具的使用。理解并掌握这些技术是优化大型数据处理的关键。
在处理大量数据时,利用多线程或多进程并行处理文件的不同部分,可以显著提升处理速度。 #### 3. 数据压缩 为了节省存储空间或网络传输时间,可以对`data.txt`文件进行压缩。常见的压缩格式有.zip、.gz等。 通过...