Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java多线程和sqlite_Java_Multithreading_Sqlite_Jdbc - Fatal编程技术网

java多线程和sqlite

java多线程和sqlite,java,multithreading,sqlite,jdbc,Java,Multithreading,Sqlite,Jdbc,我在sqlite数据库中存储了大量数据。我使用JavaJDBC驱动程序从sqlite表中批量检索数据,然后处理数据。最后,处理后的数据被重写回tabledatabase中的一个新列。由于数据的处理相当简单,我尝试使用java中的多线程来加速计算 我遵循的步骤是: 产生子线程 然后,每个子级从sqlite db读取数据并处理数据 数据处理完成后,将使用同步功能Insert and commit将其重写到数据库中。 然而,我发现在处理速度计算方面没有任何改进。事实上,随着线程数量的增加,速度也随之降

我在sqlite数据库中存储了大量数据。我使用JavaJDBC驱动程序从sqlite表中批量检索数据,然后处理数据。最后,处理后的数据被重写回tabledatabase中的一个新列。由于数据的处理相当简单,我尝试使用java中的多线程来加速计算

我遵循的步骤是:

产生子线程 然后,每个子级从sqlite db读取数据并处理数据 数据处理完成后,将使用同步功能Insert and commit将其重写到数据库中。 然而,我发现在处理速度计算方面没有任何改进。事实上,随着线程数量的增加,速度也随之降低

无多线程:

1000条记录~2分钟

2线程:1000条记录~2分钟:3秒

4个线程:1000条记录~2分钟:30秒

10个线程:1000条记录~2分钟:52秒

我使用的是Mac book pro:Mountain Lion;2.4 GHz Intel core 2 Duo 4GB 1067 MHz DDR3

代码如下:

package org.openscience.jch.diversity;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.fingerprint.MACCSFingerprinter;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.jch.utilities.IteratingMolTableReader;

/**
 *
 * @author chandu
 */
public class MultiThreadCalculator {
    // Main Class
    public static void main(String args[]) throws SQLException {
        int range = 0;
        int start = 0;
        int stop = 0;
        int a = 0;
        int numberOfThreads = 4;
        int count = 10000;
        Connection connection = connectDb("Zinc.db");
        connection.setAutoCommit(false);
        range = (int) Math.ceil(count /(double)(numberOfThreads));

        // generate the child threads and assigns them the range of rows to read from the db

        for (int i = 1; i <= numberOfThreads; i++) {
            stop = range * i;
            System.out.println(start + "," + stop);
            new NewThread(start, stop, i,connection);
            start = stop + 1;
        }
        System.out.println("Main thread exiting." + a);
    }

    // method to connect to db
    private static Connection connectDb(String path) {
         Connection c = null;
        try {
            Class.forName("org.sqlite.JDBC");
            c = DriverManager.getConnection("jdbc:sqlite:" + path);
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            System.exit(0);
        }
        System.out.println("Opened database successfully");
        return c;
    }

    // Child thread
    public static class NewThread implements Runnable {
        Thread t;
        int ii;
        int tStart = 0;
        int tStop = 0;
        static int ince = 0;
        int a = 0;
        Connection connection = null;

        NewThread(int start, int stop, int threadID, Connection c) {
            tStart = start;
            tStop = stop;
            ii = threadID;
            System.out.println("child thread"+ii);
            t = new Thread(this, "Demo Thread");
            connection = c;
            t.setPriority( Thread.NORM_PRIORITY + 1 ); 
            t.start(); 
        }

        // This is the data processing part
        public void run() {
            Map< Integer, byte[]> map = new HashMap< Integer, byte[]>();

            try (Statement stmt = connection.createStatement();
                    ResultSet rs = stmt.executeQuery("SELECT * FROM MOLDATA WHERE ID>=" + tStart + " and ID<=" + tStop + ";")) {
                //SmilesGenerator sg = new SmilesGenerator(true);
                MACCSFingerprinter mp = new MACCSFingerprinter();
                while (rs.next()) {
                    IAtomContainer molecule = null;
                    int id = rs.getInt("ID");
                    InputStream is = new ByteArrayInputStream(rs.getString("STUCTURE").getBytes());
                    IteratingMolTableReader reader = new IteratingMolTableReader(is, DefaultChemObjectBuilder.getInstance(), true);
                    while (reader.hasNext()) {
                        molecule = reader.next();
                        break;
                    }

                    byte[] bi = mp.getBitFingerprint(molecule).asBitSet().toByteArray();

                    //System.out.println(bi.length);
                    //String smiles = sg.createSMILES(molecule);
                    map.put(id, bi);
                    System.out.println(id);
                }
                stmt.close();
            } catch (Exception e) {
                System.err.println(e.getClass().getName() + ": " + e.getMessage());
                System.exit(0);
            }
            try {
                writer(connection, map);
            } catch (SQLException ex) {
                Logger.getLogger(MultiThreadCalculator.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println("Exiting child thread." + a);
        }

        // Synchronised method to insert processed data and commit changes.

        public synchronized static void writer(Connection connection, Map<Integer, byte[]> mp) throws SQLException {
            String sql = "UPDATE MOLDATA SET FP = ? WHERE ID = ?";
            PreparedStatement psUpdateRecord = connection.prepareStatement(sql);
            int[] iNoRows = null;
            for (int a : mp.keySet()) {
                byte[] bi = mp.get(a);
                psUpdateRecord.setBytes(1, bi);
                psUpdateRecord.setInt(2, a);

                psUpdateRecord.addBatch();
            }
            iNoRows = psUpdateRecord.executeBatch();
            connection.commit();
            System.out.println("Commit Done");
        }
    }
}

请记住,sqlite是一个非常小的数据库实现,针对大小和单用户/单线程使用进行了优化。您需要详细检查分析,但我预期会出现以下行为

每个线程同时读取一个数据块和其他数据块。大多数甚至所有数据都必须从磁盘读取,因为每个线程都读取另一个数据块。在这种情况下,sqlite中的缓存没有帮助,因为所有数据都不会被读取两次。当线程在访问磁盘时被序列化时,此时线程已经有效地以串行方式运行。 每个线程都进行一些复杂的计算。不管它有多复杂,它都是在内存中完成的,而sqlite在磁盘上进行读写,这要慢1000倍。 最后的插入/更新和提交完成了序列化的其余部分:提交必须写入磁盘,并且必须等待写入完成。完成该步骤后,下一个线程可以开始插入/更新其结果。 甚至可以解释线程数越多,速度也会下降:使用的线程越多,sqlite必须处理的开销就越大,而且对于许多用户或线程来说,sqlite并没有进行优化

这就是一些专业数据库变得如此昂贵的原因。它们可以处理10000个用户,并且拥有非常聪明的算法,可以让下一个东西在95%的时间内已经在内存中读取

但是你现在能做得更好吗

最实用的方法是重写代码:先从数据库中读取所有数据,然后在线程中进行处理,最后让一个线程执行所有更新/插入,最后只提交一次 您可以更改数据库,这是一个相当昂贵的解决方案。对于这种应用程序,即使是mySql也比sqlite好得多。一些数据库Oracle,Teradata。。。可以直接在数据库中运行Java代码,这样您就不需要在处理前后传输数据,这是一个常见的性能瓶颈,例如在SAS中
你做过分析吗?什么占用了时间;数据库活动还是计算?一般来说,您应该避免在多个线程之间共享同一个连接,并且每个线程有一个连接。我尝试了每个线程一个连接,但出现了错误:[SQLITE\u BUSY]数据库文件已锁定数据库已锁定。我认为Sqlite不允许在多个线程之间有多个连接。我认为问题不在于db查询调用,而在于处理数据的多线程..计算以长时间为例:为数据库中的化学结构生成MACCS结构键。。。