生产者消费者 - ExecutorService和ArrayBlockingQueue(producer consumer - ExecutorService & ArrayBlockingQueue)
我想通过使用ExecutorService和ArrayBlockingQueue来了解我对生产者消费者设计的理解是否正确。 我知道有不同的方法来实现这个设计,但我想,最后,它取决于问题本身。
我不得不面对的问题是:我有一个生产者从大文件中读取(6GB); 它逐行读取并将每一行转换为一个对象。 它将对象放在ArrayBlockingQueue中。
消费者(少数)从ArrayBlockingQueue中获取对象并将其持久保存到数据库中。
现在,显然生产者比消费者快得多; 将每一行转换为对象需要几分之一秒,但对于消费者来说需要更长的时间。
所以...如果我希望通过这样做来加速这个过程:我创建了两个分类为'ProducerThread'和'ConsumerThread'的共享ArrayBlockingQueue。 在2之间协调的线程如下所示:
@Override public void run() { try{ ArrayBlockingQueue<Ticket> queue = new ArrayBlockingQueue<Ticket>(40); ExecutorService threadPool = Executors.newFixedThreadPool(8); threadPool.execute(new SaleConsumerThread("NEW YORK", queue)); threadPool.execute(new SaleConsumerThread("PARIS", queue)); threadPool.execute(new SaleConsumerThread("TEL AVIV", queue)); threadPool.execute(new SaleConsumerThread("HONG KONG", queue)); threadPool.execute(new SaleConsumerThread("LONDON", queue)); threadPool.execute(new SaleConsumerThread("BERLIN", queue)); threadPool.execute(new SaleConsumerThread("AMSTERDAM", queue)); Future producerStatus = threadPool.submit(new SaleProducerThread(progressBar, file, queue)); producerStatus.get(); threadPool.shutdown(); }catch(Exception exp) { exp.printStackTrace(); } }
我的问题是:
上面的设计是否会同时使用每个线程? 我的电脑是两个2.4GHz四核。
我不确定Future和.get()的用途是什么?
顺便说一句,结果是快速的(考虑第一个版本是连续的,需要3小时),现在需要约40分钟(但可能还有改进的余地)。
谢谢你的指针
I wish to know if my understanding of the producer consumer design is correct by using the ExecutorService & ArrayBlockingQueue. I understand there are different ways to implement this design but I guess, at the end, it depends on the problem itself.
The problem I had to confront is this: I have a ONE producer who reads from a big file (6GB); it reads line by line and converts every line to an object. It places the object in an ArrayBlockingQueue.
The consumers (few) take the object from the ArrayBlockingQueue and persist this to the database.
Now, obviously the producer is much faster than the consumer; it takes fractions of seconds to convert each line to an object but for the consumers it takes longer time.
So...if I wish to speedup this process by doing this: I created 2 classed 'ProducerThread' and 'ConsumerThread' they share the ArrayBlockingQueue. The Thread that coordinate between the 2 looks like this:
@Override public void run() { try{ ArrayBlockingQueue<Ticket> queue = new ArrayBlockingQueue<Ticket>(40); ExecutorService threadPool = Executors.newFixedThreadPool(8); threadPool.execute(new SaleConsumerThread("NEW YORK", queue)); threadPool.execute(new SaleConsumerThread("PARIS", queue)); threadPool.execute(new SaleConsumerThread("TEL AVIV", queue)); threadPool.execute(new SaleConsumerThread("HONG KONG", queue)); threadPool.execute(new SaleConsumerThread("LONDON", queue)); threadPool.execute(new SaleConsumerThread("BERLIN", queue)); threadPool.execute(new SaleConsumerThread("AMSTERDAM", queue)); Future producerStatus = threadPool.submit(new SaleProducerThread(progressBar, file, queue)); producerStatus.get(); threadPool.shutdown(); }catch(Exception exp) { exp.printStackTrace(); } }
My questions are:
Would the design above actually use each thread concurrently? My computer is Two 2.4GHz Quad-Core.
I'm not sure what does the Future and the .get() are for?
The result, by the way, are fast (consider the first version was sequential and it took 3hr) now it takes ~40 min (but maybe there're room for improvement).
Thanks for any pointer
原文:https://stackoverflow.com/questions/10392855
最满意答案
我从文档中了解到:
limit参数控制模式的应用次数,因此会影响结果数组的长度。 如果限制n大于零,那么模式将最多应用n - 1次,数组的长度将不大于n,并且数组的最后一个条目将包含超出最后一个匹配分隔符的所有输入 。 如果n是非正数,那么模式将被应用尽可能多的次数,并且数组可以具有任何长度。 如果n为零,那么模式将被应用尽可能多的次数,该数组可以具有任何长度,并且将丢弃尾随的空字符串。
这意味着在字符串s上设计或剪切到n次,因此让我们逐一分析以更好地理解:
限制1
String[] spl1 = str.split("o", 1);
这意味着将它分割或剪切在字符串
o
上的一个字符串上,在这种情况下,您将获得所有输入:[boo:and:foo] 1
限制2
String[] spl1 = str.split("o", 2);
这意味着在
o
上减少一次,所以我会在第一个o
中断boo:and:foo -----^
在这种情况下,您将得到两个结果:
[b,o:and:foo] 1 2
限制3
String[] spl1 = str.split("o", 3);
这意味着在第一个
o
和第二个o
上切两次boo:and:foo 1----^^--------------2
在这种情况下,您将得到三个结果:
[b, ,:and:foo] 1 2 3
限制4
String[] spl1 = str.split("o", 4);
这意味着在第一,第二和第三
o
上三次削减它boo:and:foo 1_____^^ ^ |___2 |___3
在这种情况下,您将得到四个结果:
[b, ,:and:f,o] 1 2 3 4
限制5
String[] spl1 = str.split("o", 5);
这意味着在第一,第二,第三和第四次切割它四次
boo:and:foo 1_____^^ ^^ |___2 ||___4 |____3
在这种情况下,您将获得五个结果:
[b, ,:and:f, , ] 1 2 3 4 5
只是一个简单的动画来了解更多:
What i understand from the documentation :
The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array. If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
This mean devise or cut it to n time on string s, so Lets analyse one by one to understand better :
Limit 1
String[] spl1 = str.split("o", 1);
This mean split it or cut it on just one string on the string
o
in this case you will get all your input :[boo:and:foo] 1
Limit 2
String[] spl1 = str.split("o", 2);
Which mean cut it one time on
o
so i will put a break in the firsto
boo:and:foo -----^
in this case you will get two results :
[b,o:and:foo] 1 2
Limit 3
String[] spl1 = str.split("o", 3);
Which mean cut it two times on the first
o
and on the secondo
boo:and:foo 1----^^--------------2
in this case you will get three results :
[b, ,:and:foo] 1 2 3
Limit 4
String[] spl1 = str.split("o", 4);
Which mean cut it three times on the first, second and third
o
boo:and:foo 1_____^^ ^ |___2 |___3
in this case you will get four results :
[b, ,:and:f,o] 1 2 3 4
Limit 5
String[] spl1 = str.split("o", 5);
Which mean cut it four times on first, second, third and forth
o
boo:and:foo 1_____^^ ^^ |___2 ||___4 |____3
in this case you will get five results :
[b, ,:and:f, , ] 1 2 3 4 5
Just a simple animation to understand more :
相关问答
更多-
Java中的split()方法不适用于点(。)[duplicate](The split() method in Java does not work on a dot (.) [duplicate])[2023-11-24]
java.lang.String.split分割正则表达式,和. 正则表达式表示“任何字符”。 尝试temp.split("\\.") 。 java.lang.String.split splits on regular expressions, and . in a regular expression means "any character". Try temp.split("\\."). -
Java Regex Matcher可以工作,但String.split()不能(Java Regex Matcher works, but String.split() doesn't)[2023-07-03]
你正则表达式匹配整个字符串。 因此,在拆分时,整个字符串被删除。 它与"a".split("a")完全相同,它返回一个空数组。 您可以使用的是: queryText.replaceAll(".*name`([^`]+)`.*", "$1") 返回some name 。 You regex matches the whole string. Thus, when splitting, the whole string gets removed. It is exactly the sam ... -
Java - 正则表达式来分割输入文本,但保留分隔符[复制](Java - Regex to split input text but keep delimiters [duplicate])[2023-05-11]
split不是Python的findall的Java模拟。 Matcher.find是。 Pattern stuff = Pattern.compile("[\\w']+|[\\s.,!?;:-]"); Matcher matcher = stuff.matcher("Hello, this isn't working!"); ListmatchList = new ArrayList (); while (matcher.find()) { matchList.ad ... -
你应该逃避它: String words[] = word.split("\\|"); 在类似的问题在这里检查这个解释: 为什么String.split需要管道分隔符被转义? 字符串对象的split()方法有一个正则表达式作为参数。 这意味着一个非转义的| 不是解释为字符而是解释为OR,意思是“空字符串或空字符串”。 You should escape it: String words[] = word.split("\\|"); Check this explanation in similar qu ...
-
关于Java String API中的split()方法[复制](Regarding split() method in Java String API [duplicate])[2023-01-01]
如果你有一个分隔符作为第一个字符, split将返回一个空字符串作为输出数组的第一个元素(即" 10 5".split(" ")返回数组{"","10","5"} )。 同样,如果你有两个连续的分隔符, split将产生一个空的String。 所以"10 5".split(" ")会产生数组{"10","","5"} 。 如果您希望忽略前导和尾随空白,请更改str.split(" "); str.trim().split(" "); 。 If you have a delimiter as the firs ... -
用括号分割java并保留delmiter - RegEx [duplicate](java split by bracket and keep the delmiter - RegEx [duplicate])[2023-02-28]
你只是忘了在整个正则表达式周围放置捕获括号。 你根本没有抓到任何东西。 只需将正则表达式更改为 Pattern splitDelRegex = Pattern.compile("(\\([^)]*?\\))"); ^ ^ 我在Eclipse中测试了这个并得到了你想要的输出。 You simply forgot to put capturing parentheses around the entir ... -
“拆分(regEx)”和“拆分(regEx,0)”之间的Java区别?(Java difference between “split(regEx)” and “split(regEx, 0)”?)[2021-12-18]
他们基本上是一样的。 引自String.split(String regex)文档: 此方法的工作原理与通过使用给定表达式和极限参数为0调用双参数拆分方法一样。 因此,结尾的空字符串不包含在结果数组中。 They are essentially the same. Quoted from String.split(String regex) documentation: This method works as if by invoking the two-argument split method wit ... -
Java - split(regex,limit)方法实际上如何工作?(Java - How split(regex, limit) method actually works? [duplicate])[2023-12-03]
我从文档中了解到: limit参数控制模式的应用次数,因此会影响结果数组的长度。 如果限制n大于零,那么模式将最多应用n - 1次,数组的长度将不大于n,并且数组的最后一个条目将包含超出最后一个匹配分隔符的所有输入 。 如果n是非正数,那么模式将被应用尽可能多的次数,并且数组可以具有任何长度。 如果n为零,那么模式将被应用尽可能多的次数,该数组可以具有任何长度,并且将丢弃尾随的空字符串。 这意味着在字符串s上设计或剪切到n次,因此让我们逐一分析以更好地理解: 限制1 String[] spl1 = str. ... -
split状态的2-arg重载的Javadoc : 如果n为零,那么模式将被应用尽可能多的次数,该数组可以具有任何长度,并且将丢弃尾随的空字符串。 split状态的1-arg重载的Javadoc : 此方法的作用就像通过调用给定表达式和limit参数为零的双参数split方法一样。 因此,结尾的空字符串不包含在结果数组中。 并且1-arg,无限制重载相当于0的限制。 如果使用非零限制,则不再丢弃尾随空字符串。 那些不再被丢弃的尾随空字符串对应于“OCPJP”中的非空格。 The Javadocs for t ...
-
默认情况下,MongoDB在与count一起应用时忽略limit并skip 。 要更改此行为,您需要将applySkipLimit设置为true 。 有关详细信息,请参见此处 在Mongo shell中,这将忽略limit并默认skip : db.coll.find().limit(3).count(); 这将尊重这些修饰符: db.coll.find().limit(3).count(true); 您可能正在使用旧版本的Mongo shell,这不是默认版本或类似的东西。 要修复Java代码,请使用s ...